Showing posts with label procedure. Show all posts
Showing posts with label procedure. Show all posts

Friday, March 30, 2012

Rownumber()

I am trying to write a stored procedure to be used for custompaging and I get error with the below SP.
"Msg 207, Level 16, State 1, Procedure GetDealersPagedSP, Line 14 Invalid column name 'RowRank'."

What am I doing wrong?

CREATEPROCEDURE dbo.GetDealerSP

(
@.startRowIndexint,
@.maximumRowsint
)
As
SELECT installersemaid,dealerid,[name],address1,address2,city,[state],
zip,phone,fax
From
(
SELECT installersemaid,dealerid,[name],address1,address2,city,[state],
zip,phone,fax,ROW_NUMBER()OVER(ORDERBY [name]DESC)AS Rowbank
FROM dealerenrollment)as DealerWithRowNumbers
WHERE Rowbank> @.startRowIndexAND RowRank<=(@.startRowIndex+ @.maximumRows)
Go

Hi bhavin78,

bhavin78:

"Msg 207, Level 16, State 1, Procedure GetDealersPagedSP, Line 14 Invalid column name 'RowRank'."

...

CREATEPROCEDURE dbo.GetDealerSP

...

WHERE Rowbank> @.startRowIndexANDRowRank<=(@.startRowIndex+ @.maximumRows)
Go


Looks like it's a typo, that RowRank should be Rowbank according to the rest of your query.

Personally, I'd change the three instances of Rowbank to RowRank, as it's a little closer to describing the columns contents (actually, calling it RowNumber would be my first choice ;) ).

I hope that helps.

|||

--zip,phone,fax, ROW_NUMBER() OVER(ORDER BY [name] DESC)ASRowbank

You have used Rowbank not RowRank check it once

Monday, March 26, 2012

ROW_NUMBER() function is not recognized in store procedure.

Hello I am Prasad , I have written one store procedure as below. But It gives error message ROW_NUMBER() function is not recognized. what's the fault or what should i change.

CREATE PROCEDURE GetProductsOnCatalogPromotion
(@.DescriptionLength INT,
@.PageNumber INT,
@.ProductsPerPage INT,
@.HowManyProducts INT OUTPUT)
AS
-- declare a new TABLE variable
DECLARE @.Products TABLE
(RowNumber INT,
ProductID INT,
Name VARCHAR(50),
Description VARCHAR(5000),
Price MONEY,
Image1FileName VARCHAR(50),
Image2FileName VARCHAR(50),
OnDepartmentPromotion bit,
OnCatalogPromotion bit)
-- populate the table variable with the complete list of products
INSERT INTO @.Products
SELECTROW_NUMBER() OVER (ORDER BY Product.ProductID),
ProductID, Name,
SUBSTRING(Description, 1, @.DescriptionLength) + '...' AS Description, Price,
Image1FileName, Image2FileName, OnDepartmentPromotion, OnCatalogPromotion
FROM Product
WHERE OnCatalogPromotion = 1
-- return the total number of products using an OUTPUT variable
SELECT @.HowManyProducts = COUNT(ProductID) FROM @.Products
-- extract the requested page of products
SELECT ProductID, Name, Description, Price, Image1FileName,
Image2FileName, OnDepartmentPromotion, OnCatalogPromotion
FROM @.Products
WHERERowNumber > (@.PageNumber - 1) * @.ProductsPerPage
ANDRowNumber <= @.PageNumber * @.ProductsPerPage

What version of SQL Server is this running on? ROW_NUMBER() was introduced in 2005, so any version before that won't have it.

Don

|||

Hello,I create database in sql2000 but when i got this error. I connect it with sql2005 (same database).and tried to run this store proc. but same error occurs in sql2005. I dint create database in sql2005 only open in sql2005 and tried.

I want to fetch records for paging purpose by its row numbers. so i tried this store proc. is there any other way to fetch without row numbers?

please reply.

|||

prasad bhanage:

Hello,I create database in sql2000 but when i got this error. I connect it with sql2005 (same database).and tried to run this store proc. but same error occurs in sql2005. I dint create database in sql2005 only open in sql2005 and tried.

Row_number() is a T-SQL enhancement that has been introduced in SQL 2005 only. If your database is in SQL 2000 you can't use any of the features introduced after SQL 2000 even if you run them using SQL 2005 tools. visithttp://msdn2.microsoft.com/en-us/library/ms186734.aspx for more information.

Now, to solve you problem as you've SQL 2000, there is one way of using temporary table for this. Your modified procedure is as below. Please make the logical changes as you wish.

CREATE PROCEDURE GetProductsOnCatalogPromotion(@.DescriptionLengthINT,@.PageNumberINT,@.ProductsPerPageINT,@.HowManyProductsINT OUTPUT)ASSELECT identity (bigint , 1 , 1 )as RowNumber , ProductID ,Name ,SUBSTRING(Description , 1 , @.DescriptionLength ) +'...'AS Description , Price , Image1FileName , Image2FileName , OnDepartmentPromotion , OnCatalogPromotioninto #ProductsFROM ProductWHERE OnCatalogPromotion = 1order by Product.ProductIDSELECT @.HowManyProducts =COUNT ( ProductID )FROM #ProductsSELECT ProductID ,Name ,Description , Price , Image1FileName ,Image2FileName , OnDepartmentPromotion , OnCatalogPromotionFROM #ProductsWHERE RowNumber > ( @.PageNumber - 1 ) * @.ProductsPerPageAND RowNumber <= @.PageNumber * @.ProductsPerPage

Hope this will help.


|||

Hi,

You need to create the database in sqlserver 2005.

Then only it will work other wise u can't use perticular keyword in Sql Server 2000.

It was newly introduced in sqlserver 2005 Only.

_____________________________________________________________

Mark as Answer If u find a solution.

Wednesday, March 21, 2012

Row numbering unpredictable

Hi,
I need to create a stored procedure that returns the row number (for
paging) AFTER the data has been sorted with an order by. The source is
a view. The code I have is:
SELECT rownum = IDENTITY(1,1,bigint), *
INTO #tmp
FROM viewName
ORDER BY CustomerName -- field name I'm ordering by
When I recieve the results back, the rownum column is not the same
order as the customername (it jumps half way to a high number?!?),
which means I can't page it based on rownum without jumping all over
the dataset.
Anyone got any ideas on how to solve that other than client side paging
(in ADO :-P)
This is SQL 2000 SP3 (pah!)
Cheers,
Chris Smith
http://www.cswd.co.uk/Assuming CustomerName is unique:
select
(select count (*)
from #tmp t1
where t1.CustomerName <= t2.CustomerName) as rownum
, *
from
#tmp t2
order by
t2.CustomerName
Tom
----
Thomas A. Moreau, BSc, PhD, MCSE, MCDBA
SQL Server MVP
Toronto, ON Canada
.
<cseemeuk@.googlemail.com> wrote in message
news:1144755017.455143.6760@.v46g2000cwv.googlegroups.com...
Hi,
I need to create a stored procedure that returns the row number (for
paging) AFTER the data has been sorted with an order by. The source is
a view. The code I have is:
SELECT rownum = IDENTITY(1,1,bigint), *
INTO #tmp
FROM viewName
ORDER BY CustomerName -- field name I'm ordering by
When I recieve the results back, the rownum column is not the same
order as the customername (it jumps half way to a high number?!?),
which means I can't page it based on rownum without jumping all over
the dataset.
Anyone got any ideas on how to solve that other than client side paging
(in ADO :-P)
This is SQL 2000 SP3 (pah!)
Cheers,
Chris Smith
http://www.cswd.co.uk/|||you could create the table first with an ID column, then insert into
it. I suspect (though have no evidence) that the select into #tmp with
an id column created then is having issues with the order by|||(cseemeuk@.googlemail.com) writes:
> I need to create a stored procedure that returns the row number (for
> paging) AFTER the data has been sorted with an order by. The source is
> a view. The code I have is:
> SELECT rownum = IDENTITY(1,1,bigint), *
> INTO #tmp
> FROM viewName
> ORDER BY CustomerName -- field name I'm ordering by
> When I recieve the results back, the rownum column is not the same
> order as the customername (it jumps half way to a high number?!?),
> which means I can't page it based on rownum without jumping all over
> the dataset.
> Anyone got any ideas on how to solve that other than client side paging
Create the table with CREATE TABLE, and then use INSERT with SELECT ORDER
BY. Add OPTION (MAXDOP 1) as an extra precaution. I've been told from MS
people that it's guaranteed to work. Whether that really is true, I'm not
completely convinced of, but fairly. In any case, SELECT INTO is *not*
guaranteed to work that way, so stay away from it.
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se
Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pr...oads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodin...ions/books.mspx|||Thanks - works perfectly. The INTO was the problem - appears to be no
guaranteed order to the IDENTITY(bigint, 1,1)
All sorted
Cheers,
Chris Smith
http://www.cswd.co.uk/|||The order is not guaranteed when you use SELECT INTO.
See
http://support.microsoft.com/defaul...kb;en-us;273586
For a list of paging options see
http://www.aspfaq.com/show.asp?id=2120
Regards
Roji. P. Thomas
http://toponewithties.blogspot.com
<cseemeuk@.googlemail.com> wrote in message
news:1144755017.455143.6760@.v46g2000cwv.googlegroups.com...
> Hi,
> I need to create a stored procedure that returns the row number (for
> paging) AFTER the data has been sorted with an order by. The source is
> a view. The code I have is:
> SELECT rownum = IDENTITY(1,1,bigint), *
> INTO #tmp
> FROM viewName
> ORDER BY CustomerName -- field name I'm ordering by
> When I recieve the results back, the rownum column is not the same
> order as the customername (it jumps half way to a high number?!?),
> which means I can't page it based on rownum without jumping all over
> the dataset.
> Anyone got any ideas on how to solve that other than client side paging
> (in ADO :-P)
> This is SQL 2000 SP3 (pah!)
> Cheers,
> Chris Smith
> http://www.cswd.co.uk/
>|||One would think this type of thing,so common and important,
would have a kb or something written by MS.Are you aware of any
link?If none exists I would ask you to kindly request something in
'writing'.Key points of an enterprise database should not be rattling
around just in someone head! :)
Clarity,clarity and nothing but clarity.
Regards from:
www.rac4sql.net
"Erland Sommarskog" <esquel@.sommarskog.se> wrote in message
news:Xns97A28BF07D031Yazorman@.127.0.0.1...
> (cseemeuk@.googlemail.com) writes:
> Create the table with CREATE TABLE, and then use INSERT with SELECT ORDER
> BY. Add OPTION (MAXDOP 1) as an extra precaution. I've been told from MS
> people that it's guaranteed to work. Whether that really is true, I'm not
> completely convinced of, but fairly. In any case, SELECT INTO is *not*
> guaranteed to work that way, so stay away from it.
>
> --
> Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se
> Books Online for SQL Server 2005 at
> http://www.microsoft.com/technet/pr...oads/books.mspx
> Books Online for SQL Server 2000 at
> http://www.microsoft.com/sql/prodin...ions/books.mspx|||Steve Dassin wrote:
> One would think this type of thing,so common and important,
> would have a kb or something written by MS.Are you aware of any
> link?If none exists I would ask you to kindly request something in
> 'writing'.Key points of an enterprise database should not be rattling
> around just in someone head! :)
> Clarity,clarity and nothing but clarity.
http://support.microsoft.com/defaul...kb;en-us;273586
Do not assume that article means that all INSERTs will always cause
IDENTITY to be generated in a predetermined order. There are at least
some situations where that doesn't work - whether by design or a bug I
can't say.
Perhaps the safest course is to assume that you cannot control the
IDENTITY sequence with ORDER BY. In my view the wisest and most logical
solution is to use other methods like the ROW_NUMBER function for
example.
I can think of at least two good reasons for not using IDENTITY the way
proposed by the KB. Firstly IDENTITY is normally intended as an
arbitrary surrogate key - using the values in any "meaningful" way is a
compromise you don't need and is something it just isn't designed for.
Secondly, this supposed behaviour of an "ordered" INSERT looks contrary
to the set-based nature of an INSERT statement. Whether or not it works
today, it seems undesirable to assume that it should always work that
way in future. One would hope and expect that the engine could optimise
out any redundant sorting in INSERT...SELECT queries. That seems to be
what happens in some cases today and maybe it will happen more often in
future versions due to improvements in the optimiser. Just some things
to bear in mind.
David Portas, SQL Server MVP
Whenever possible please post enough code to reproduce your problem.
Including CREATE TABLE and INSERT statements usually helps.
State what version of SQL Server you are using and specify the content
of any error messages.
SQL Server Books Online:
http://msdn2.microsoft.com/library/ms130214(en-US,SQL.90).aspx
--|||>> Anyone got any ideas on how to solve that other than client side paging <
<
The basic principle of a tiered architecture is that display is done in
the front end adn NEVER in the database. Why are you sing violating
40 years of Software Engineering?|||"--CELKO--" <jcelko212@.earthlink.net> wrote in message
news:1144803667.948395.290650@.i40g2000cwc.googlegroups.com...
<<
> The basic principle of a tiered architecture is that display is done in
> the front end adn NEVER in the database. Why are you sing violating
> 40 years of Software Engineering?
>
Forty years of a life sentence is enough.Time to let the innocent free.
Convicted on trumped up,unsubstantiated and false charges.In other words,
NONSENSE.
The thread:
Monday, April 10, 2006 9:48 PM
microsoft.public.sqlserver.programming
Re: Membership Timeline Spanning
contains a response that further clarifies things:
"Itzik Ben-Gan" writes
>.
>In my previous reply I mentioned the ANSI OVER clause (with an ORDER BY
>option). It is really brilliant, and I wonder if the designers of the
>feature themselves knew how profound it is. I believe this option to be the
>bridge between cursors and sets; sort of the holy grail of SQL. :-)
To quote Bob Dylan:
'I would not feel so alone if everyone where getting stoned':)
Yes I agree with you in principal.The 'real' paradign shift has
little to do with the clr and everything to do with exploding
the perverted myth of the exclusivity of'set based' constructs.
The idea one can legitimately think in terms of rows without being
labelled an sql Jodus has arrived.But calling this windowing a
'profound' kind of insight and bestowing on the designers the aura
of 'brilliance' would be a mistake.It is at best an example of
'better late than never'.Calling this state of affairs profound
would surely overshadow the accountability that the commericial
database world should be held to.The fact that this mindset change
has taken almost 30 years should be seen as appalling.Neo-cons of
the industry had hijacked sense with sql creationism and marketing.
WMD was replaced with client/server and a tiered approach.A theory
was misapplied to a retrival mechanism and unapplied to a design
mechanism.An approach that vendors marketted that allowed them to
hide both their intellectual and creative shortcomings.Their db
failures made for the 'client'.And now the clr in the db has replaced
the client.And of course the dreaded cursor.This demanded regime
change and the field was bankrupted for 30 years.For this we are to
praise Ceasar?I think not.
It is interesting to look at the fanfare that vendors are using
to usher in this new paradign.In their documentation Oracle refers
to their analytic functions in windows as an example of
'data densification'.This phrase is supposed to illustrate the
flip side of the Group By.It was obviously borrowed from the idea
of pacification,right out of the Pentagon.This is the best they could
come up with?Any army of engineers berefit of language and concepts.
Not to be out done,MS in its highly touted BOL offers the next best
thing - absolutely Nothing!No explanations,no history no seqways.
The functions are thrown around like so much spaghetti on a wall.
If you write about concepts someone may quote you.MS needn't worry
now.Least I be accused of favortism,IBM was too busy pleasing its
shareholders to write anything intelligible.
Finally,to your point about MS leaving out a large chunk of analytic
material this was obviously not an oversight but just insurance
that anything done with sql-99 could most definitly be easily ported
to the competition.Less is more.Please!If they weren't sure of
what they were doing they could have at least looked at Oracle
which is probably about 8 years ahead.Or even looked at RAC to see what
you and I are really talking about :)
Interested readers maybe surprised that many of the ideas in sql
analytics can be found in the SAS (Statistical Analysis System) Data
Step...introduced about 20 years ago!Many of the Oracle extensions
(First/Last) can also be found here.MySql allows mixing of variables
and columns in a SELECT.Most of the analytics can be easily simulated
in a single SELECT.And of course little RAC, way ahead of its time:)
Some musing from:
www.rac4sql.net

row num

can i have the row number in a select like ROWNUM in Oracle DB?
:confused:
I want to to

create procedure sp_table1_sel( @.startRow bigint, @.endRow bintint)
AS
SELECT *
FROM table1
WHER rownum < @.startRow
AND rownum > @.endRow

How can I do that?!

ThanksCheck this SQL TEAM (http://www.sqlteam.com/item.asp?ItemID=1491) link.|||Originally posted by Satya
Check this SQL TEAM (http://www.sqlteam.com/item.asp?ItemID=1491) link.

OK I read something like this in the MSDN mag (may 2003) but if a have 60 000 rows in the table? The query take 30 sec...

something better?!

Row Not Inserting At Bottom

Greetings, SQLanoids,

When I insert a row of data into a table via a stored procedure, the row SOMETIMES gets inserted at the bottom, and sometimes gets inserted at another random location (top, midding, etc). I am using Microsoft SQL Server.

Dea anybody know the cause of this? Or how to ensure that the row gets inserted at the bottom?

I am a novice SQL Server user, but this seems like a simple problem that the more advanced users solved long ago. Thanks in advance!This behavior you are seeing is by design. SQL Server decides where to put the data and we have no control over that. Nor, really, is it important.

If you need the data to come out of the database in a particular order, you need to use an ORDER BY statement. If it is important for you to know the order in which records were inserted into the database, I suggest using a DateAdded column with a Default Value of GETDATE() so that SQL Server will automatically populate this for you. You might also consider using a column flagged as an IDENTITY for this purpose.

Terri|||Thank you for the response. I tried your advice and it worked well. However, I noticed only one problem.

When it inserts the date, using a Default Value of GETDATE(), and using data type smalldatetime, the field gets inserted as "1/17/2005 2:23:00 AM".

However, when I set the data type to vnarchar, the field gets inserted as "Jan 17 2005 2:23AM"

I prefer the second method, as it spells out the first 3 letters of the month. The problem, however, is that the ORDER BY statement does not accurately pull the records when stored as nvarchar. It is unable to distinguish between AM and PM and pulls the records in order of numeric chronology only.

Do you know how I can fix this, and still store the items as "Jan..."?

Thanks|||Use a datetime data type to store datetime data. Use output formatting to display the data in the desired format (either by using CAST or CONVERT, or in the ASP.NET front end).

Terri

Tuesday, March 20, 2012

row level permissions

is there a simple procedure to run to find what the row level permissions are on each user?

thanks.

I am not clear with the requirement. There is no row level permission in sql server if its refering to Table rows. You can give table level permission or you can create views as per the conditions and give permission to views.

Madhu

|||I should clearify. I'm looing for table level permissions. I assume there is a simple procedure to run to find this information for each user.|||

Take a look at the INFORMATION_SCHEMA.TABLE_PRIVILEGES view. This might provide the detail you're looking for.

HTH!

|||

or you can use sp_helprotect /sys.database_permissions and fn_builtin_permissions to get the permission on objects.

Read about

SP_HELPROTECT/sys.database_permissions (sql server 2005) in BOL

Madhu

Monday, March 12, 2012

Row Counts for every user table in a database?

Hello again, everyone!
I'm attempting to make a stored procedure that gets the rowcount for every
table in a given database. To do this, obviously, I need to use a cursor.
The problem I'm having is with passing the database name to the procedure,
and having it evaluate and run the expression. Here is my code thus far:
----
--
create procedure z_sp_CountTest
@.DatabaseName nvarchar(100)
as
-- Declare the Variables
Declare
@.SQL nvarchar(300),
@.DatabaseSysObjects nvarchar(100),
@.TableName sysname
-- Make a string for the database name and table to get all table names from
Set @.DatabaseSysObjects = @.DatabaseName + '.dbo.sysobjects'
-- Create a SQL string to get the user table names
Set @.SQL = 'Select name from ' + @.DatabaseSysObjects + ' where xtype = ''U''
order by name'
-- Declare the cursor to get the Table Names
Declare GetTableRowCounts Cursor
Local
For
exec master.dbo.sp_executesql @.SQL
Open GetTableRowCounts
Fetch next from GetTableRowCounts into @.TableName
While (@.@.FETCH_STATUS = 0)
Begin
[Do what I want with the rowcounts here.. Will require a statement similiar
to the above]
End
CLOSE GetTableRowCounts
DEALLOCATE GetTableRowCounts
----
--
However, whenever I do a syntax check, I always get:
Server: Msg 156, Level 15, State 1, Procedure z_sp_CountTest, Line 21
Incorrect syntax near the keyword 'exec'.
Can anyone give me a clue as to what it could possibly be?
I've tried almost every itteration of the exec line I could think of. This
includes leaving the master.dbo out, trying just exec, and many other
hair-brainned ideas.
Any help would be great!You'll probably have to dump the results from the @.SQL into a temp table and
run the cursor on the temp table.
-D
"Adam St. Pierre" <AdamStPierre@.discussions.microsoft.com> wrote in message
news:006956CB-2309-457C-BA49-FE08D5BB3894@.microsoft.com...
> Hello again, everyone!
> I'm attempting to make a stored procedure that gets the rowcount for every
> table in a given database. To do this, obviously, I need to use a cursor.
> The problem I'm having is with passing the database name to the procedure,
> and having it evaluate and run the expression. Here is my code thus far:
> ----
--
> create procedure z_sp_CountTest
> @.DatabaseName nvarchar(100)
> as
> -- Declare the Variables
> Declare
> @.SQL nvarchar(300),
> @.DatabaseSysObjects nvarchar(100),
> @.TableName sysname
> -- Make a string for the database name and table to get all table names
> from
> Set @.DatabaseSysObjects = @.DatabaseName + '.dbo.sysobjects'
> -- Create a SQL string to get the user table names
> Set @.SQL = 'Select name from ' + @.DatabaseSysObjects + ' where xtype =
> ''U''
> order by name'
>
> -- Declare the cursor to get the Table Names
> Declare GetTableRowCounts Cursor
> Local
> For
> exec master.dbo.sp_executesql @.SQL
> Open GetTableRowCounts
> Fetch next from GetTableRowCounts into @.TableName
> While (@.@.FETCH_STATUS = 0)
> Begin
> [Do what I want with the rowcounts here.. Will require a statement
> similiar
> to the above]
> End
> CLOSE GetTableRowCounts
> DEALLOCATE GetTableRowCounts
> ----
--
>
> However, whenever I do a syntax check, I always get:
> Server: Msg 156, Level 15, State 1, Procedure z_sp_CountTest, Line 21
> Incorrect syntax near the keyword 'exec'.
> Can anyone give me a clue as to what it could possibly be?
> I've tried almost every itteration of the exec line I could think of. This
> includes leaving the master.dbo out, trying just exec, and many other
> hair-brainned ideas.
>
> Any help would be great!
>|||Adam,
You can use a non-documented sp sp_msforeachtable (not recommended in
production code) or create a cursor to traverse information_schema.tables.
You can also pull that info from the system table sysindexes, but be sure to
first execute "dbcc updateusage (...) with count_rows".
use northwind
go
exec sp_msforeachtable 'select ''?'', count(*) from ?'
go
create table #t (
tname sysname,
rcnt int
)
declare @.tn sysname
declare @.sql nvarchar(4000)
declare my_cursor cursor local fast_forward
for
select
quotename(table_schema) + '.' + quotename(table_name)
from
information_schema.tables
where
objectproperty(object_id(quotename(table
_schema) + '.' +
quotename(table_name)), 'IsUserTable') = 1
and objectproperty(object_id(quotename(table
_schema) + '.' +
quotename(table_name)), 'IsMSShipped') = 0
open my_cursor
while 1 = 1
begin
fetch next from my_cursor into @.tn
if @.@.error != 0 or @.@.fetch_status != 0 break
set @.sql = N'select ''' + @.tn + N''', count(*) from ' + @.tn
insert into #t
exec sp_executesql @.sql
end
close my_cursor
deallocate my_cursor
select * from #t order by 1
drop table #t
go
dbcc updateusage (0) with count_rows
go
select object_name([id]) as table_name, rowcnt
from sysindexes
where indid in (0, 1) and objectproperty([id], 'IsUserTable') = 1
order by 1
go
AMB
"Adam St. Pierre" wrote:

> Hello again, everyone!
> I'm attempting to make a stored procedure that gets the rowcount for every
> table in a given database. To do this, obviously, I need to use a cursor.
> The problem I'm having is with passing the database name to the procedure,
> and having it evaluate and run the expression. Here is my code thus far:
> ----
--
> create procedure z_sp_CountTest
> @.DatabaseName nvarchar(100)
> as
> -- Declare the Variables
> Declare
> @.SQL nvarchar(300),
> @.DatabaseSysObjects nvarchar(100),
> @.TableName sysname
> -- Make a string for the database name and table to get all table names fr
om
> Set @.DatabaseSysObjects = @.DatabaseName + '.dbo.sysobjects'
> -- Create a SQL string to get the user table names
> Set @.SQL = 'Select name from ' + @.DatabaseSysObjects + ' where xtype = ''U
''
> order by name'
>
> -- Declare the cursor to get the Table Names
> Declare GetTableRowCounts Cursor
> Local
> For
> exec master.dbo.sp_executesql @.SQL
> Open GetTableRowCounts
> Fetch next from GetTableRowCounts into @.TableName
> While (@.@.FETCH_STATUS = 0)
> Begin
> [Do what I want with the rowcounts here.. Will require a statement simili
ar
> to the above]
> End
> CLOSE GetTableRowCounts
> DEALLOCATE GetTableRowCounts
> ----
--
>
> However, whenever I do a syntax check, I always get:
> Server: Msg 156, Level 15, State 1, Procedure z_sp_CountTest, Line 21
> Incorrect syntax near the keyword 'exec'.
> Can anyone give me a clue as to what it could possibly be?
> I've tried almost every itteration of the exec line I could think of. This
> includes leaving the master.dbo out, trying just exec, and many other
> hair-brainned ideas.
>
> Any help would be great!
>|||Adam,

> Declare GetTableRowCounts Cursor
> Local
> For
> exec master.dbo.sp_executesql @.SQL
When declaring a cursor, a select statement should go after "For". The
"exec" command is not allow here.
AMB
"Adam St. Pierre" wrote:

> Hello again, everyone!
> I'm attempting to make a stored procedure that gets the rowcount for every
> table in a given database. To do this, obviously, I need to use a cursor.
> The problem I'm having is with passing the database name to the procedure,
> and having it evaluate and run the expression. Here is my code thus far:
> ----
--
> create procedure z_sp_CountTest
> @.DatabaseName nvarchar(100)
> as
> -- Declare the Variables
> Declare
> @.SQL nvarchar(300),
> @.DatabaseSysObjects nvarchar(100),
> @.TableName sysname
> -- Make a string for the database name and table to get all table names fr
om
> Set @.DatabaseSysObjects = @.DatabaseName + '.dbo.sysobjects'
> -- Create a SQL string to get the user table names
> Set @.SQL = 'Select name from ' + @.DatabaseSysObjects + ' where xtype = ''U
''
> order by name'
>
> -- Declare the cursor to get the Table Names
> Declare GetTableRowCounts Cursor
> Local
> For
> exec master.dbo.sp_executesql @.SQL
> Open GetTableRowCounts
> Fetch next from GetTableRowCounts into @.TableName
> While (@.@.FETCH_STATUS = 0)
> Begin
> [Do what I want with the rowcounts here.. Will require a statement simili
ar
> to the above]
> End
> CLOSE GetTableRowCounts
> DEALLOCATE GetTableRowCounts
> ----
--
>
> However, whenever I do a syntax check, I always get:
> Server: Msg 156, Level 15, State 1, Procedure z_sp_CountTest, Line 21
> Incorrect syntax near the keyword 'exec'.
> Can anyone give me a clue as to what it could possibly be?
> I've tried almost every itteration of the exec line I could think of. This
> includes leaving the master.dbo out, trying just exec, and many other
> hair-brainned ideas.
>
> Any help would be great!
>|||> I've been told that sometimes this method isn't completely up to date, but I've come acro
ss a
> situation like that yet.
There are plenty such operations and situations, but it has been improved wi
th each version. But in
2005, it should be considered an exception of this isn't up to date. Below i
s a scrip to show this,
and note that even regular INSERTs can make the values go out of whack. On 2
005 the information is
up to date, though:
-- Pre stuff
SET NOCOUNT ON
USE Credit
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
CREATE TABLE #tmp (seq int IDENTITY (1, 1), RowsInTable int, Comment varchar
(200), indid smallint,
dpages int, reserved int, used int, rowcnt int, statblob image )
GO
---
-- INSERT
---
IF OBJECT_ID('charge2') IS NOT NULL DROP TABLE charge2
SELECT * INTO charge2 FROM charge WHERE 1=0
CREATE CLUSTERED INDEX charge_member_link ON dbo.charge2(member_no)
CREATE INDEX charge_category_link ON dbo.charge2(category_no)
CREATE INDEX charge_charge_amt ON dbo.charge2(charge_amt)
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'Table created with SELEC
T INTO, index created',
indid, dpages, reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
-- Regular INSERTs
DECLARE @.c INT SELECT @.c = 0
WHILE @.c < 5000
BEGIN
INSERT charge2(member_no, provider_no, category_no, charge_dt, charge_amt, s
tatement_no,
charge_code)
VALUES( 63, 482, 8, 'Sep 18 1997 10:43AM', 503.00, 20063, ' ')
SELECT @.c = @.c + 1
END
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'After a bunch of regular
INSERTs', indid,
dpages, reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
-- UPDATE STATISTICS
UPDATE STATISTICS charge2
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'After UPDATE STATISTICS'
, indid, dpages,
reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
---
-- DELETE
---
-- We have a table with 5000 rows, make sure columns in sysindexes are updat
ed
DBCC UPDATEUSAGE(credit, charge2) WITH COUNT_ROWS
--Regular DELETE
SET ROWCOUNT 4000 DELETE FROM charge2 SET ROWCOUNT 0
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'After UPDATEUSAGE and DE
LETE of 4000 rows',
indid, dpages, reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
---
-- TRUNCATE TABLE
---
-- Make sure we have updated sysindexes for 5000 rows
IF OBJECT_ID('charge2') IS NOT NULL DROP TABLE charge2
SELECT * INTO charge2 FROM charge
CREATE CLUSTERED INDEX charge_member_link ON dbo.charge2(member_no)
CREATE INDEX charge_category_link ON dbo.charge2(category_no)
CREATE INDEX charge_charge_amt ON dbo.charge2(charge_amt)
DBCC UPDATEUSAGE(credit, charge2) WITH COUNT_ROWS
TRUNCATE TABLE charge2
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'Had 5000 rows with corre
ct space usages, then
TRUNCATE TABLE', indid, dpages, reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
---
-- INSERT with subselect
---
-- Get a new fresh empty charge2 without identity
IF OBJECT_ID('charge2') IS NOT NULL DROP TABLE charge2
CREATE TABLE dbo.charge2
(charge_no int NOT NULL ,member_no int NOT NULL ,provider_no int NOT NULL, c
ategory_no int NOT
NULL,
charge_dt datetime NOT NULL , charge_amt money NOT NULL ,statement_no int NO
T NULL, charge_code
char(2) NOT NULL)
GO
CREATE CLUSTERED INDEX charge_member_link ON dbo.charge2(member_no)
CREATE INDEX charge_category_link ON dbo.charge2(category_no)
CREATE INDEX charge_charge_amt ON dbo.charge2(charge_amt)
SET ROWCOUNT 5000 INSERT charge2 SELECT * FROM charge SET ROWCOUNT 0
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'After INSERT with SUBSEL
ECT', indid, dpages,
reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
---
-- SELECT INTO
---
IF OBJECT_ID('charge2') IS NOT NULL DROP TABLE charge2
SELECT * INTO charge2 FROM charge
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'After SELECT INTO', indi
d, dpages, reserved,
used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
---
-- CREATE INDEX
---
IF OBJECT_ID('charge2') IS NOT NULL DROP TABLE charge2
SELECT * INTO charge2 FROM charge
CREATE CLUSTERED INDEX charge_member_link ON dbo.charge2(member_no)
CREATE INDEX charge_category_link ON dbo.charge2(category_no)
CREATE INDEX charge_charge_amt ON dbo.charge2(charge_amt)
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'After CREATE INDEX', ind
id, dpages, reserved,
used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
-- Update the tables representation in sysindexes before creating the other
indexes
DROP INDEX charge2.charge_category_link
DROP INDEX charge2.charge_charge_amt
DROP INDEX charge2.charge_member_link
DBCC UPDATEUSAGE(credit, charge2) WITH COUNT_ROWS
CREATE CLUSTERED INDEX charge_member_link ON dbo.charge2(member_no)
CREATE INDEX charge_category_link ON dbo.charge2(category_no)
CREATE INDEX charge_charge_amt ON dbo.charge2(charge_amt)
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'Dropped indexes, DBCC UP
DATEUSAGE and created
indexes', indid, dpages, reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
---
-- SLOW BCP
---
IF OBJECT_ID('charge2') IS NOT NULL DROP TABLE charge2
SELECT * INTO charge2 FROM charge
-- BCP out
EXEC master..xp_cmdshell 'bcp credit..charge2 out c:\charge.txt /t"[]" /r\n
/c /T', 'no_output'
-- Empty table with 3 indexes -> slow bcp
TRUNCATE TABLE charge2
CREATE CLUSTERED INDEX charge_member_link ON dbo.charge2(member_no)
CREATE INDEX charge_category_link ON dbo.charge2(category_no)
CREATE INDEX charge_charge_amt ON dbo.charge2(charge_amt)
DBCC UPDATEUSAGE(credit, charge2) WITH COUNT_ROWS
-- BCP in
EXEC master..xp_cmdshell 'bcp credit..charge2 in c:\charge.txt /t"[]" /r\n /
c /T', 'no_output'
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'After slow BCP into empt
y table', indid, dpages,
reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
---
-- FAST BCP
---
IF OBJECT_ID('charge2') IS NOT NULL DROP TABLE charge2
SELECT * INTO charge2 FROM charge WHERE 1 = 0
-- BCP in
EXEC master..xp_cmdshell 'bcp credit..charge2 in c:\charge.txt /t"[]" /r\n /
c /T /h"TABLOCK"',
'no_output'
INSERT #tmp SELECT (SELECT COUNT(*) FROM charge2), 'After fast BCP into empt
y table', indid, dpages,
reserved, used, rowcnt, statblob
FROM sysindexes WHERE id = OBJECT_ID('charge2') order by indid
GO
SELECT * FROM #tmp WHERE indid IN(0,1) ORDER BY seq, indid
Tibor Karaszi, SQL Server MVP
http://www.karaszi.com/sqlserver/default.asp
http://www.solidqualitylearning.com/
Blog: http://solidqualitylearning.com/blogs/tibor/
"Colin Dawson" <newsgroups@.cjdawson.com> wrote in message
news:xJyYf.47848$wl.40101@.text.news.blueyonder.co.uk...
> Who needs a cursor? How about using
> select
> so.name,
> si.rows
> from sysobjects so
> Join sysindexes si on si.id = so.id
> and si.indid in (0,1)
> where so.xtype = 'U'
>
> I've been told that sometimes this method isn't completely up to date, but
I've come across a
> situation like that yet. Mind you, I've not been looking.
>
> Colin.
>
> "Adam St. Pierre" <AdamStPierre@.discussions.microsoft.com> wrote in messag
e
> news:006956CB-2309-457C-BA49-FE08D5BB3894@.microsoft.com...
>|||<snip>
> There are plenty such operations and situations, but it has been improved
> with each version. But in 2005, it should be considered an exception of
> this isn't up to date. Below is a scrip to show this, and note that even
> regular INSERTs can make the values go out of whack. On 2005 the
> information is up to date, though:
</snip>
I suppose that I'm really lucky to be working soley with SQL2005 now :-)
Colin.

Friday, March 9, 2012

Row Count

I am writing a Insert stored procedure that has logic which is going to
do different things based on the results of a query.
The query is going to do a count. If the count is not equal to 0, then
the procedure returns setting a @.msg paramenter and -1 in the return
code.
I can get this working just fine, but when the count > 0, a rowset is
returned and I am not wanting the rowset returned. Is there someway to
structure the procedure such that a rowset is not returned Here is
what I have...
alter proc Proc_InsertCompetativeEvents
@.Name char(50),
@.City char(50),
@.State char(50),
@.StartDt smalldatetime,
@.EndDt smalldatetime,
@.msg nvarchar(220) out
as
declare @.cnt int
select count(CompetitionName)
from dbo.CompetativeEvents
where CompetitionName = @.name
group by CompetitionName
if @.@.ROWCOUNT > 0
begin
set @.msg = 'Duplicate Event Names are not allowed'
return -1
end
insert into dbo.CompetativeEvents
Values (newid(), @.Name,@.City,@.State,@.StartDt, @.EndDt)
set @.cnt = @.@.ROWCOUNT
if @.@.ERROR > 0
begin
set @.msg = 'Unexpected error occurred inserting a record into
CompetativeEvents using the Proc_InsertCompetativeEvents procedure -
Error code: ' + cast(@.@.ERROR as char(4))
return -1
end
if @.cnt = 1
begin
set @.msg=''
return 0
end
set @.msg = 'Beat me what happen'
return -1
Thanks in advance for your assistance!!!!!!!!Use IF EXISTS:
IF EXISTS
(SELECT *
FROM CompetitiveEvents
WHERE competitionname = @.name)
SET @.msg = 'Duplicate Event Names are not allowed'
...
--
David Portas
--
Please reply only to the newsgroup
--|||Jim,
I'm not sure what you want, but could you explain what you are
intending to do with
select count(CompetitionName) ...
if @.@.ROWCOUNT > 0
If I'm not mistaken, @.@.ROWCOUNT will always be greater than zero after a
select count() query.
Your narrative says that you want to compare the count with zero, but
your code does not compare the count with zero. It compares the number
of count(CompetitionName) values returned (the rowcount of the query)
with zero, and that value looks like it will always be 1, since you
restrict to CompetitionName = @.name before grouping.
SK
Jim Heavey wrote:
>I am writing a Insert stored procedure that has logic which is going to
>do different things based on the results of a query.
>The query is going to do a count. If the count is not equal to 0, then
>the procedure returns setting a @.msg paramenter and -1 in the return
>code.
>I can get this working just fine, but when the count > 0, a rowset is
>returned and I am not wanting the rowset returned. Is there someway to
>structure the procedure such that a rowset is not returned Here is
>what I have...
>alter proc Proc_InsertCompetativeEvents
> @.Name char(50),
> @.City char(50),
> @.State char(50),
> @.StartDt smalldatetime,
> @.EndDt smalldatetime,
> @.msg nvarchar(220) out
>as
>declare @.cnt int
>select count(CompetitionName)
> from dbo.CompetativeEvents
> where CompetitionName = @.name
> group by CompetitionName
>if @.@.ROWCOUNT > 0
> begin
> set @.msg = 'Duplicate Event Names are not allowed'
> return -1
> end
>insert into dbo.CompetativeEvents
> Values (newid(), @.Name,@.City,@.State,@.StartDt, @.EndDt)
>set @.cnt = @.@.ROWCOUNT
>if @.@.ERROR > 0
> begin
> set @.msg = 'Unexpected error occurred inserting a record into
>CompetativeEvents using the Proc_InsertCompetativeEvents procedure -
>Error code: ' + cast(@.@.ERROR as char(4))
> return -1
> end
>if @.cnt = 1
> begin
> set @.msg=''
> return 0
> end
>set @.msg = 'Beat me what happen'
>return -1
>
>Thanks in advance for your assistance!!!!!!!!
>|||Jim Heavey (JimHeavey@.nospam.com) writes:
> I can get this working just fine, but when the count > 0, a rowset is
> returned and I am not wanting the rowset returned. Is there someway to
> structure the procedure such that a rowset is not returned Here is
> what I have...
As Steve pointed out, this does not make sense:
> declare @.cnt int
> select count(CompetitionName)
> from dbo.CompetativeEvents
> where CompetitionName = @.name
> group by CompetitionName
> if @.@.ROWCOUNT > 0
What you most likely want is:
SELECT @.cnt = COUNT(*)
FROM CompetativeEvents
WHERE CompetitionName = @.name
IF @.cnt > 0
(Note that I also left out GROUP BY.)
Of course, even better is David's suggestion to use IF EXISTS. Not much
of an issue here, but if there could be 1000 rows, and you are only
interested whether in 0 or not zero, there is no reason to count them
all.
Erland Sommarskog, SQL Server MVP, sommar@.algonet.se
Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinfo/productdoc/2000/books.asp|||> If I'm not mistaken, @.@.ROWCOUNT will always be greater than zero after a
> select count() query.
Because the query includes GROUP BY, @.@.ROWCOUNT will return 0 if the @.name
doesn't exist but it will never be more than 1 because of the combination of
GROUP BY and the WHERE clause.
Since the point seems to be to test for the presence or absence of a value I
suggested using EXISTS. Of course, another option is just to do the insert
and trap the error at the client rather than pass a message from the SP.
--
David Portas
--
Please reply only to the newsgroup
--|||David Portas wrote:
>>If I'm not mistaken, @.@.ROWCOUNT will always be greater than zero after a
>>select count() query.
>>
>Because the query includes GROUP BY, @.@.ROWCOUNT will return 0 if the @.name
>doesn't exist but it will never be more than 1 because of the combination of
>GROUP BY and the WHERE clause.
>
Oops - good catch. This is one place where GROUP BY can reduce the
number of rows returned...
SK
>Since the point seems to be to test for the presence or absence of a value I
>suggested using EXISTS. Of course, another option is just to do the insert
>and trap the error at the client rather than pass a message from the SP.
>
>|||Hi
As an aside, the following code will be problematic if an error occurs:
insert into dbo.CompetativeEvents
Values (newid(), @.Name,@.City,@.State,@.StartDt, @.EndDt)
set @.cnt = @.@.ROWCOUNT
if @.@.ERROR > 0
The set resets the @.@.ERROR variable back to 0 so if an error occurs during
the insert, you don't get it.
To resolve this, store the error in a variable and get both values back at
the same time:
SELECT @.cnt = @.@.ROWCOUNT, @.LocalError = @.@.Error
if @.LocalError > 0
Regards
--
Mike Epprecht, Microsoft SQL Server MVP
Epprecht Consulting (PTY) LTD
Johannesburg, South Africa
Mobile: +27-82-552-0268
IM: mike@.NOSPAMepprecht.net
Specialist SQL Server Solutions and Consulting
"Jim Heavey" <JimHeavey@.nospam.com> wrote in message
news:Xns9465C570A8BFEJimHeaveyhotmailcom@.207.46.248.16...
> I am writing a Insert stored procedure that has logic which is going to
> do different things based on the results of a query.
> The query is going to do a count. If the count is not equal to 0, then
> the procedure returns setting a @.msg paramenter and -1 in the return
> code.
> I can get this working just fine, but when the count > 0, a rowset is
> returned and I am not wanting the rowset returned. Is there someway to
> structure the procedure such that a rowset is not returned Here is
> what I have...
> alter proc Proc_InsertCompetativeEvents
> @.Name char(50),
> @.City char(50),
> @.State char(50),
> @.StartDt smalldatetime,
> @.EndDt smalldatetime,
> @.msg nvarchar(220) out
> as
> declare @.cnt int
> select count(CompetitionName)
> from dbo.CompetativeEvents
> where CompetitionName = @.name
> group by CompetitionName
> if @.@.ROWCOUNT > 0
> begin
> set @.msg = 'Duplicate Event Names are not allowed'
> return -1
> end
> insert into dbo.CompetativeEvents
> Values (newid(), @.Name,@.City,@.State,@.StartDt, @.EndDt)
> set @.cnt = @.@.ROWCOUNT
> if @.@.ERROR > 0
> begin
> set @.msg = 'Unexpected error occurred inserting a record into
> CompetativeEvents using the Proc_InsertCompetativeEvents procedure -
> Error code: ' + cast(@.@.ERROR as char(4))
> return -1
> end
> if @.cnt = 1
> begin
> set @.msg=''
> return 0
> end
> set @.msg = 'Beat me what happen'
> return -1
>
> Thanks in advance for your assistance!!!!!!!!

Row by Row Processing

I am trying to create a procedure within SQL Server 2000 that will update a
table for viewing over our intranet(nightly process). The final output will
show current balances within accounts.
The way the logic works for calculating the accounts is that the accounts
are allocated by years.
Example:
2001 ACCOUNT1
2002 ACCOUNT1
2001 ACCOUNT2
2003 ACCOUNT2
etc.....
Expenses occur over multiple years and must be applied to the earliest
year/account that exists. If the balance of the year/account is zero, then
look at the next year (if it exists) to apply the expense (expenses could be
split between 2 years).
What I have in the SQL server is a table with the accounts and balances, and
a seperate view with the expenditures. I want to take the view and "walk"
through record by record updating the table with current balances. I have
never done this before in SQL server and wonder if it can be done. We would
like to do it in the SQL Server because then the SQL server handles all the
data updating, etc. on it's own and we don't have to worry about an external
process to update this table.
I'm looking for an example, or guidance on what is the best way to perform
this task.
Thanks.You should go for a rowbased solution. YOu didnt post soe DDL, so we
cansee wheter the new data will be stored in existing tables (then you
should use an update) or in a new table (Then you should use ainsert or
select into). perhaps you can give some more information about that.
HTH, Jens Suessmeyer.
http://www.sqlserver2005.de
--
"Lyners" <Lyners@.discussions.microsoft.com> schrieb im Newsbeitrag
news:742DBEF6-85F1-47B8-8F6C-3F8B668ECDE9@.microsoft.com...
>I am trying to create a procedure within SQL Server 2000 that will update a
> table for viewing over our intranet(nightly process). The final output
> will
> show current balances within accounts.
> The way the logic works for calculating the accounts is that the accounts
> are allocated by years.
> Example:
> 2001 ACCOUNT1
> 2002 ACCOUNT1
> 2001 ACCOUNT2
> 2003 ACCOUNT2
> etc.....
> Expenses occur over multiple years and must be applied to the earliest
> year/account that exists. If the balance of the year/account is zero, then
> look at the next year (if it exists) to apply the expense (expenses could
> be
> split between 2 years).
> What I have in the SQL server is a table with the accounts and balances,
> and
> a seperate view with the expenditures. I want to take the view and "walk"
> through record by record updating the table with current balances. I have
> never done this before in SQL server and wonder if it can be done. We
> would
> like to do it in the SQL Server because then the SQL server handles all
> the
> data updating, etc. on it's own and we don't have to worry about an
> external
> process to update this table.
> I'm looking for an example, or guidance on what is the best way to perform
> this task.
> Thanks.
>|||hi
just look at CURSORs in SQL Server Books Online. U can traverse row-by-row
was this the one u are looking for?
best Regards,
Chandra
http://chanduas.blogspot.com/
http://groups.msn.com/SQLResource/
---
"Lyners" wrote:

> I am trying to create a procedure within SQL Server 2000 that will update
a
> table for viewing over our intranet(nightly process). The final output wil
l
> show current balances within accounts.
> The way the logic works for calculating the accounts is that the accounts
> are allocated by years.
> Example:
> 2001 ACCOUNT1
> 2002 ACCOUNT1
> 2001 ACCOUNT2
> 2003 ACCOUNT2
> etc.....
> Expenses occur over multiple years and must be applied to the earliest
> year/account that exists. If the balance of the year/account is zero, then
> look at the next year (if it exists) to apply the expense (expenses could
be
> split between 2 years).
> What I have in the SQL server is a table with the accounts and balances, a
nd
> a seperate view with the expenditures. I want to take the view and "walk"
> through record by record updating the table with current balances. I have
> never done this before in SQL server and wonder if it can be done. We woul
d
> like to do it in the SQL Server because then the SQL server handles all th
e
> data updating, etc. on it's own and we don't have to worry about an extern
al
> process to update this table.
> I'm looking for an example, or guidance on what is the best way to perform
> this task.
> Thanks.
>|||@.OG: But rather using cursor you should always prefer using rowbased
statements. In common you can say that cursor are slower than rowbased
statements.
HTH, Jens Suessmeyer.
http://www.sqlserver2005.de
--
"Chandra" <chandra@.discussions.microsoft.com> schrieb im Newsbeitrag
news:C9B5793C-2D15-48DA-96DC-8CB91DFD4338@.microsoft.com...
> hi
> just look at CURSORs in SQL Server Books Online. U can traverse row-by-row
> was this the one u are looking for?
> --
> best Regards,
> Chandra
> http://chanduas.blogspot.com/
> http://groups.msn.com/SQLResource/
> ---
>
> "Lyners" wrote:
>|||You could use a cursor for this, but cursors on large rowsets can be slow.
It sounds like what you are trying to do could be better implemented by
joining to a sub-query.
"Lyners" <Lyners@.discussions.microsoft.com> wrote in message
news:742DBEF6-85F1-47B8-8F6C-3F8B668ECDE9@.microsoft.com...
> I am trying to create a procedure within SQL Server 2000 that will update
a
> table for viewing over our intranet(nightly process). The final output
will
> show current balances within accounts.
> The way the logic works for calculating the accounts is that the accounts
> are allocated by years.
> Example:
> 2001 ACCOUNT1
> 2002 ACCOUNT1
> 2001 ACCOUNT2
> 2003 ACCOUNT2
> etc.....
> Expenses occur over multiple years and must be applied to the earliest
> year/account that exists. If the balance of the year/account is zero, then
> look at the next year (if it exists) to apply the expense (expenses could
be
> split between 2 years).
> What I have in the SQL server is a table with the accounts and balances,
and
> a seperate view with the expenditures. I want to take the view and "walk"
> through record by record updating the table with current balances. I have
> never done this before in SQL server and wonder if it can be done. We
would
> like to do it in the SQL Server because then the SQL server handles all
the
> data updating, etc. on it's own and we don't have to worry about an
external
> process to update this table.
> I'm looking for an example, or guidance on what is the best way to perform
> this task.
> Thanks.
>|||Please post DDL, so that people do not have to guess what the keys,
constraints, Declarative Referential Integrity, datatypes, etc. in your
schema are. Sample data is also a good idea, along with clear
specifications.|||The best way to get help with your problem is to post DDL, sample data
and required results. See:
http://www.aspfaq.com/etiquett=ADe.asp?id=3D5006
I doubt that row-by-row processing is the best solution. Pobably you
can do this with an UPDATE or SELECT statement.
--=20
David Portas=20
SQL Server MVP=20
--|||Thanks Jens,
for the update. I was suposed to mention that but clicked send before
mentioning that. I normally suggest people not to use cursors as they consum
e
a lotof time and memory.
best Regards,
Chandra
http://chanduas.blogspot.com/
http://groups.msn.com/SQLResource/
---
"Jens Sü?meyer" wrote:

> @.OG: But rather using cursor you should always prefer using rowbased
> statements. In common you can say that cursor are slower than rowbased
> statements.
> --
> HTH, Jens Suessmeyer.
> --
> http://www.sqlserver2005.de
> --
> "Chandra" <chandra@.discussions.microsoft.com> schrieb im Newsbeitrag
> news:C9B5793C-2D15-48DA-96DC-8CB91DFD4338@.microsoft.com...
>
>|||It's OK to admit that we all use cursors on occasion. They can be convenient
so long as the rowset is small. A lot of the system stored procedures in
MASTER are implemented using cursors, so we can't avoid them.
"Chandra" <chandra@.discussions.microsoft.com> wrote in message
news:1101D390-347A-45C3-AA4B-78577F8A4080@.microsoft.com...
> Thanks Jens,
> for the update. I was suposed to mention that but clicked send before
> mentioning that. I normally suggest people not to use cursors as they
consume
> a lotof time and memory.
>
> --
> best Regards,
> Chandra
> http://chanduas.blogspot.com/
> http://groups.msn.com/SQLResource/
> ---
>
> "Jens Smeyer" wrote:
>
row-by-row
update
output
accounts
earliest
could
balances,
"walk"
have
all|||I got it working... kind of. My problem is the select at the end. it appears
that the @.vchNextExpenseFiscalYearID are being reset. I set the
@.vchNextExpenseFiscalYearID by a select statement, but there is another quer
y
with the same field name (FiscalYear) that pulls into another varable. Does
SQL Server 2000 set a varable so that it is static so it is set to the year
(i.e. 2003), or is my varable (@.vchNextExpenseFiscalYearID) dynamic and set
to the field FiscalYear, so it changes with the field?
Please note that I did not use Cursors or Fetch next. I didn't use cursors
because of the resource use, and I didn't use Fetch Next because I did not
realize there was such a command until I was close to the end.
here is my code:
CREATE PROCEDURE dbo.loadunspentbonds AS
delete from unspentbonds
insert into unspentbonds(fiscalyear, project, subproject, bondamount,
UnspentBond) select fiscalyear, project, subproject, bondamount, bondamount
from vwUnspentBondsbudgetprior2005
insert into unspentbonds(fiscalyear, project, subproject, bondamount,
UnspentBond) select fiscalyear, project, subproject, bondamount, bondamount
from vwUnspentBondsbudgetafter2004
/* Update the Unspent Bond table with Expenditures and the current bond amou
nt
** We use a row by row processing to achieve our results because expenditure
s
** go back to the first year of the bonds
*/
SET NOCOUNT ON
-- declare all variables!
DECLARE @.iReturnCode int,
@.vchNextProjectID nvarchar(5),
@.vchNextSubProjectID nvarchar(2),
@.vchNextFiscalYearID nvarchar(4),
@.vchCurrentProjectID nvarchar(5),
@.vchCurrentSubProjectID nvarchar(2),
@.vchCurrentFiscalYearID nvarchar(4),
@.iExpenseLoopControl int,
@.vchNextExpenseProjectID nvarchar(5),
@.vchNextExpenseSubProjectID nvarchar(2),
@.vchNextExpenseFiscalYearID nvarchar(4),
@.vchCurrentExpenseProjectID nvarchar(5),
@.vchCurrentExpenseSubProjectID nvarchar(2),
@.vchCurrentExpenseFiscalYearID nvarchar(4),
@.fltGLExpendedAmount float,
@.fltUnspentBondAmount float
-- Initialize variables
SELECT @.iExpenseLoopControl = 1
SELECT TOP 1 @.vchNextExpenseProjectID = Project,
@.vchNextExpenseSubProjectID = SubProject,
@.vchNextExpenseFiscalYearID = FiscalYear
FROM [CapitalFinance].[dbo]. [vwUnspentBondsDailyExpendituresAfter200
4]
-- Make sure the table has data
if isnull(@.vchNextExpenseProjectID,'') = ''
BEGIN
RETURN
END
-- Retrieve the first Unspent Bond Row
SELECT TOP 1 @.vchCurrentExpenseProjectID = Project,
@.vchCurrentExpenseSubProjectID = SubProject,
@.vchCurrentExpenseFiscalYearID =
FiscalYear,
@.fltGLExpendedAmount = GLExpended
FROM [CapitalFinance].[dbo]. [vwUnspentBondsDailyExpendituresAfter200
4]
WHERE Project = @.vchNextExpenseProjectID and
SubProject = @.vchNextExpenseSubProjectID and
FiscalYear = @.vchNextExpenseFiscalYearID
WHILE @.iExpenseLoopControl = 1
BEGIN
-- Begin the nested(inner) loop.
-- Get the first Unspent Bond for the current Expense Record
SELECT @.vchNextProjectID = Project,
@.vchNextSubProjectID = SubProject,
@.vchNextFiscalYearID = FiscalYear
FROM [CapitalfINANCE].[dbo].[UnspentBonds]
WHERE Project = @.vchCurrentExpenseProjectID and
SubProject = @.vchCurrentExpenseSubProjectID
--make sure that the Unspent Bond exists
if isnull(@.vchNextProjectID,"") <> ""
BEGIN
WHILE @.vchNextProjectID = @.vchCurrentExpenseProjectID and
@.vchNextSubProjectID = @.vchCurrentExpenseSubProjectID
BEGIN
-- Get the first Unspent Bond for the current Expense Record
SELECT @.vchCurrentProjectID = Project,
@.vchCurrentSubProjectID = SubProject,
@.vchCurrentFiscalYearID = FiscalYear,
@.fltUnspentBondAmount = UnspentBond
FROM [CapitalfINANCE].[dbo].[UnspentBonds]
WHERE Project = @.vchNextProjectID and
SubProject = @.vchNextSubProjectID and
FiscalYear = @.vchNextFiscalYearID
IF @.fltGLExpendedAmount < @.fltUnspentBondAmount
BEGIN
UPDATE [CapitalfINANCE].[dbo].[UnspentBonds]
SET unspentBond = @.fltUnspentBondAmount - @.fltGLExpendedAmount,
ExpenditureAmount = ExpenditureAmount +
@.fltGLExpendedAmount
WHERE Project = @.vchCurrentProjectID and
SubProject = @.vchCurrentSubProjectID and
FiscalYear = @.vchCurrentFiscalYearID
SELECT @.fltGLExpendedAmount = 0
END
ELSE
BEGIN
SELECT @.fltGLExpendedAmount = @.fltGLExpendedAmount -
@.fltUnspentBondAmount
UPDATE [CapitalfINANCE].[dbo].[UnspentBonds]
SET unspentBond = 0,
ExpenditureAmount = ExpenditureAmount + @.fltUnspentBondAmount
WHERE Project = @.vchCurrentProjectID and
SubProject = @.vchCurrentSubProjectID and
FiscalYear = @.vchCurrentFiscalYearID
END
SELECT @.vchNextProjectID = Project,
@.vchNextSubProjectID = SubProject,
@.vchNextFiscalYearID = FiscalYear
FROM [CapitalfINANCE].[dbo].[UnspentBonds]
WHERE Project + SubProject + FiscalYear > @.vchNextProjectID +
@.vchNextSubProjectID + @.vchNextFiscalYearID
END
END
SELECT TOP 1 @.vchNextExpenseProjectID = Project,
@.vchNextExpenseSubProjectID = SubProject,
@.vchNextExpenseFiscalYearID = FiscalYear
FROM [CapitalFinance].[dbo]. [vwUnspentBondsDailyExpendituresAfter200
4]
WHERE Project + SubProject + FiscalYear >
@.vchCurrentExpenseProjectID + @.vchCurrentExpenseSubProjectID +
@.vchCurrentExpenseFiscalYearID
BEGIN
-- Make sure the table has data
if isnull(@.vchnextExpenseProjectID,"") = ""
BEGIN
BREAK
END
SELECT @.vchCurrentExpenseProjectID = Project,
@.vchCurrentExpenseSubProjectID = SubProject,
@.vchCurrentExpenseFiscalYearID = FiscalYear,
@.fltGLExpendedAmount = GLExpended
FROM [CapitalFinance].[dbo]. [vwUnspentBondsDailyExpendituresAfter200
4]
WHERE Project = @.vchNextExpenseProjectID and
SubProject = @.vchNextExpenseSubProjectID and
FiscalYear = @.vchNextExpenseFiscalYearID
END
RETURN
GO
"Lyners" wrote:

> I am trying to create a procedure within SQL Server 2000 that will update
a
> table for viewing over our intranet(nightly process). The final output wil
l
> show current balances within accounts.
> The way the logic works for calculating the accounts is that the accounts
> are allocated by years.
> Example:
> 2001 ACCOUNT1
> 2002 ACCOUNT1
> 2001 ACCOUNT2
> 2003 ACCOUNT2
> etc.....
> Expenses occur over multiple years and must be applied to the earliest
> year/account that exists. If the balance of the year/account is zero, then
> look at the next year (if it exists) to apply the expense (expenses could
be
> split between 2 years).
> What I have in the SQL server is a table with the accounts and balances, a
nd
> a seperate view with the expenditures. I want to take the view and "walk"
> through record by record updating the table with current balances. I have
> never done this before in SQL server and wonder if it can be done. We woul
d
> like to do it in the SQL Server because then the SQL server handles all th
e
> data updating, etc. on it's own and we don't have to worry about an extern
al
> process to update this table.
> I'm looking for an example, or guidance on what is the best way to perform
> this task.
> Thanks.
>

Row by Row Copy

I'm writing a stored procedure that requires I duplicate records through a loop, one record at a time (required because I need to execute SCOPE_IDENTITY() logic on each insertion). But each row has 40 or so columns, making my stored procedure ridiculously full of long declaration lists. So I want to either:

1) Learn a way to auto-insert the column declarations into my code without having to type them all by hand, or...

2) Learn a way to represent the whole row for insertion, without having to specify each column specifically.

The latter solution would be the most elegant, but I'll take what I can get...

how about this?

--

IDENTITY (Function)

Is used only in a SELECT statement with an INTO table clause to insert an identity column into a new table.

Although similar, the IDENTITY function is not the IDENTITY property that is used with CREATE TABLE and ALTER TABLE.

Syntax

IDENTITY ( data_type [ , seed , increment ] ) AS column_name

Arguments

data_type

Is the data type of the identity column. Valid data types for an identity column are any data types of the integer data type category (except for the bit data type), or decimal data type.

seed

Is the value to be assigned to the first row in the table. Each subsequent row is assigned the next identity value, which is equal to the last IDENTITY value plus the increment value. If neither seed nor increment is specified, both default to 1.

increment

Is the increment to add to the seed value for successive rows in the table.

column_name

Is the name of the column that is to be inserted into the new table.

Return Types

Returns the same as data_type.

Remarks

Because this function creates a column in a table, a name for the column must be specified in the select list in one of these ways:

--(1)

SELECT IDENTITY(int, 1,1) AS ID_Num

INTO NewTable

FROM OldTable

--(2)

SELECT ID_Num = IDENTITY(int, 1, 1)

INTO NewTable

FROM OldTable

Examples

This example inserts all rows from the employee table from the pubs database into a new table called employees. The IDENTITY function is used to start identification numbers at 100 instead of 1 in the employees table.

USE pubs

IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES

WHERE TABLE_NAME = 'employees')

DROP TABLE employees

GO

EXEC sp_dboption 'pubs', 'select into/bulkcopy', 'true'

SELECT emp_id AS emp_num,

fname AS first,

minit AS middle,

lname AS last,

IDENTITY(smallint, 100, 1) AS job_num,

job_lvl AS job_level,

pub_id,

hire_date

INTO employees

FROM employee

GO

USE pubs

EXEC sp_dboption 'pubs', 'select into/bulkcopy', 'false'

|||

What version of SQL Server are you using? In SQL Server 2005, you can use OUTPUT clause in INSERT statement to get the generated identity values for multiple rows easily. See the link below for a post that describes one example:

http://blogs.msdn.com/sqltips/archive/2005/06/13/OUTPUT_clause.aspx

You can do the same in older versions by dumping the key values into a temporary table created in the SP from the trigger and accessing it from outside. This will still be much more efficient than what you are doing and run many times faster. And you kinda lost me on why you ned the declare list etc. You can do the looping without cursors.

|||

I'm using 2005. I need more than just the newly generated identity values...I also need the original identity values from the records being copied. Like:

old_ID new_ID

4 227

63 228

65 229

I need this "pairing" of old and new, because I am copying both "parents" and "children" of 1-to-many relationships. To fetch and copy the children, I need to know the parent's "copy from" old id (to get the children) and the parent's "copy to" new id (to correlate the new copies of children to the new parent ids).

So I don't really care to explicitly "handle" each and every column of the parent - I don't care what the contents of those columns are - I just want to copy them. So it is really annoying to have an "INTO" clause where I've got a comma delimited list of 40 columns...which I only ever intend on copying without ever inspecting. The only thing I am "inspecting" is the values of the identity (primary key) of the parent.

Perhaps SQL Server 2005 has a "do what I mean" stored proc I can execute...

|||

Ok. This is kind of tricky with OUTPUT clause and INSERT because you can only reference INSERTED table columns / expressions. You can however do it easily using a technique like below:

create table T ( i int not null identity primary key, j int null references T(i));
insert into T (j) values(null) ;
insert into T (j) values(scope_identity());
select * from T;

declare @.t table(i int not null);
set transaction isolation level serializable;
begin tran;
insert into T (j)
output inserted.i into @.t( i)
select j from T order by i;

select t2.i as old_i, t1.i as new_i
from (select i, ROW_NUMBER() OVER(order by i) from @.t) as t1(i, seq)
join (select i, ROW_NUMBER() OVER(order by i) from T) as t2(i, seq)
on t1.seq = t2.seq;

commit;

select * from T;

drop table T;

The trick is to insert the rows into the table in a particular order (you can choose multiple columns if you want). In the code above, the ORDER BY in the SELECT statement of INSERT ensures that the generated identity values are in the same order. You can then sequence the old and newly generated values & join based on the sequence. The serializable transaction is however required since it is not easy to protect the identity values generation in case of concurrent inserts to the table. This technique will work for you if this operation is an expensive one (replicating portions of tree) and you are doing it infrequently. This set-based approach should be much simpler than what you have but there is nothing in the SQL language to simplify column lists. You have to specify those you want to SELECT or use. That is how the language is defined.

|||

Wow, that is quite the solution. I think I need just a wee more help...since I am so rusty/inexperienced with T/SQL.

Firstly, you have a "select * from T" statement near the top of your script that doesn't seem to do anything. Is it just a piece of debug/sanity check output - or is it necessary for the solution?

Secondly, it seems to me that when I turn my attention towards copying records in the child table - I still might need to resort to explicit looping while using your "old-to-new" correlation query. That is, after I copy the child's records, I will need to change the foreign key on each child row, to reflect the new foreign keys in the parent. There are perhaps two ways I can think of to avoid such explicit looping:

1) If the child table also has an identity column (primary key), then I can repeat the magical "old-to-new" correlation query for the child table's insert as well. Then, after the insert (copy) on the child is done, I would do an update on the child's newly inserted rows - predicated on a 3-way inner join between the parent's "old-to-new" recordset, the child's "old-to-new" recordset, and the child itself. Phew!!!

2) After duplicating the relevant child records in the child, I would need to use a facility in SQL Server 2005 that allows me to perform an update only on the newly added child records. Perhaps this just means using the "inserted" virtual table again. As such, I perceive a simpler variation of proposal (1) above. That is, I "save" the contents of the "inserted" rows into a temp table. Then I perform an update predicated on a 3-way inner join between the parent's "old-to-new," the "inserted" temp table, and the child itself. This still supposes that the child has its own identity (primary key) column.

Even if you concur with either of the above strategies, is there an alternative you prefer?

|||The main logic is the part between the declare table and the commit tran. The rest of the code was just to show the rows. I didn't quite understand the part about copying child rows. Please post a simple DDL and data like in my example. And also the expected results so it will be easier to suggest a modified solution or show how my previous example can be used.|||

I made the effort to implement the rest of what I needed, and discovered that producing copies of the child records was nothing as difficult as I anticipated. I did not need a unique primary key in the children, and I did not need looping. Just an insert statement predicated on a simple join. Thats all.

So, in short, you have shown me how to produce all the copies I needed, without using looping structures. Therefore I will mark your primary response as the answer.

Row by Row Copy

I'm writing a stored procedure that requires I duplicate records through a loop, one record at a time (required because I need to execute SCOPE_IDENTITY() logic on each insertion). But each row has 40 or so columns, making my stored procedure ridiculously full of long declaration lists. So I want to either:

1) Learn a way to auto-insert the column declarations into my code without having to type them all by hand, or...

2) Learn a way to represent the whole row for insertion, without having to specify each column specifically.

The latter solution would be the most elegant, but I'll take what I can get...

how about this?

--

IDENTITY (Function)

Is used only in a SELECT statement with an INTO table clause to insert an identity column into a new table.

Although similar, the IDENTITY function is not the IDENTITY property that is used with CREATE TABLE and ALTER TABLE.

Syntax

IDENTITY ( data_type [ , seed , increment ] ) AS column_name

Arguments

data_type

Is the data type of the identity column. Valid data types for an identity column are any data types of the integer data type category (except for the bit data type), or decimal data type.

seed

Is the value to be assigned to the first row in the table. Each subsequent row is assigned the next identity value, which is equal to the last IDENTITY value plus the increment value. If neither seed nor increment is specified, both default to 1.

increment

Is the increment to add to the seed value for successive rows in the table.

column_name

Is the name of the column that is to be inserted into the new table.

Return Types

Returns the same as data_type.

Remarks

Because this function creates a column in a table, a name for the column must be specified in the select list in one of these ways:

--(1)

SELECT IDENTITY(int, 1,1) AS ID_Num

INTO NewTable

FROM OldTable

--(2)

SELECT ID_Num = IDENTITY(int, 1, 1)

INTO NewTable

FROM OldTable

Examples

This example inserts all rows from the employee table from the pubs database into a new table called employees. The IDENTITY function is used to start identification numbers at 100 instead of 1 in the employees table.

USE pubs

IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES

WHERE TABLE_NAME = 'employees')

DROP TABLE employees

GO

EXEC sp_dboption 'pubs', 'select into/bulkcopy', 'true'

SELECT emp_id AS emp_num,

fname AS first,

minit AS middle,

lname AS last,

IDENTITY(smallint, 100, 1) AS job_num,

job_lvl AS job_level,

pub_id,

hire_date

INTO employees

FROM employee

GO

USE pubs

EXEC sp_dboption 'pubs', 'select into/bulkcopy', 'false'

|||

What version of SQL Server are you using? In SQL Server 2005, you can use OUTPUT clause in INSERT statement to get the generated identity values for multiple rows easily. See the link below for a post that describes one example:

http://blogs.msdn.com/sqltips/archive/2005/06/13/OUTPUT_clause.aspx

You can do the same in older versions by dumping the key values into a temporary table created in the SP from the trigger and accessing it from outside. This will still be much more efficient than what you are doing and run many times faster. And you kinda lost me on why you ned the declare list etc. You can do the looping without cursors.

|||

I'm using 2005. I need more than just the newly generated identity values...I also need the original identity values from the records being copied. Like:

old_ID new_ID

4 227

63 228

65 229

I need this "pairing" of old and new, because I am copying both "parents" and "children" of 1-to-many relationships. To fetch and copy the children, I need to know the parent's "copy from" old id (to get the children) and the parent's "copy to" new id (to correlate the new copies of children to the new parent ids).

So I don't really care to explicitly "handle" each and every column of the parent - I don't care what the contents of those columns are - I just want to copy them. So it is really annoying to have an "INTO" clause where I've got a comma delimited list of 40 columns...which I only ever intend on copying without ever inspecting. The only thing I am "inspecting" is the values of the identity (primary key) of the parent.

Perhaps SQL Server 2005 has a "do what I mean" stored proc I can execute...

|||

Ok. This is kind of tricky with OUTPUT clause and INSERT because you can only reference INSERTED table columns / expressions. You can however do it easily using a technique like below:

create table T ( i int not null identity primary key, j int null references T(i));
insert into T (j) values(null) ;
insert into T (j) values(scope_identity());
select * from T;

declare @.t table(i int not null);
set transaction isolation level serializable;
begin tran;
insert into T (j)
output inserted.i into @.t( i)
select j from T order by i;

select t2.i as old_i, t1.i as new_i
from (select i, ROW_NUMBER() OVER(order by i) from @.t) as t1(i, seq)
join (select i, ROW_NUMBER() OVER(order by i) from T) as t2(i, seq)
on t1.seq = t2.seq;

commit;

select * from T;

drop table T;

The trick is to insert the rows into the table in a particular order (you can choose multiple columns if you want). In the code above, the ORDER BY in the SELECT statement of INSERT ensures that the generated identity values are in the same order. You can then sequence the old and newly generated values & join based on the sequence. The serializable transaction is however required since it is not easy to protect the identity values generation in case of concurrent inserts to the table. This technique will work for you if this operation is an expensive one (replicating portions of tree) and you are doing it infrequently. This set-based approach should be much simpler than what you have but there is nothing in the SQL language to simplify column lists. You have to specify those you want to SELECT or use. That is how the language is defined.

|||

Wow, that is quite the solution. I think I need just a wee more help...since I am so rusty/inexperienced with T/SQL.

Firstly, you have a "select * from T" statement near the top of your script that doesn't seem to do anything. Is it just a piece of debug/sanity check output - or is it necessary for the solution?

Secondly, it seems to me that when I turn my attention towards copying records in the child table - I still might need to resort to explicit looping while using your "old-to-new" correlation query. That is, after I copy the child's records, I will need to change the foreign key on each child row, to reflect the new foreign keys in the parent. There are perhaps two ways I can think of to avoid such explicit looping:

1) If the child table also has an identity column (primary key), then I can repeat the magical "old-to-new" correlation query for the child table's insert as well. Then, after the insert (copy) on the child is done, I would do an update on the child's newly inserted rows - predicated on a 3-way inner join between the parent's "old-to-new" recordset, the child's "old-to-new" recordset, and the child itself. Phew!!!

2) After duplicating the relevant child records in the child, I would need to use a facility in SQL Server 2005 that allows me to perform an update only on the newly added child records. Perhaps this just means using the "inserted" virtual table again. As such, I perceive a simpler variation of proposal (1) above. That is, I "save" the contents of the "inserted" rows into a temp table. Then I perform an update predicated on a 3-way inner join between the parent's "old-to-new," the "inserted" temp table, and the child itself. This still supposes that the child has its own identity (primary key) column.

Even if you concur with either of the above strategies, is there an alternative you prefer?

|||The main logic is the part between the declare table and the commit tran. The rest of the code was just to show the rows. I didn't quite understand the part about copying child rows. Please post a simple DDL and data like in my example. And also the expected results so it will be easier to suggest a modified solution or show how my previous example can be used.|||

I made the effort to implement the rest of what I needed, and discovered that producing copies of the child records was nothing as difficult as I anticipated. I did not need a unique primary key in the children, and I did not need looping. Just an insert statement predicated on a simple join. Thats all.

So, in short, you have shown me how to produce all the copies I needed, without using looping structures. Therefore I will mark your primary response as the answer.

Wednesday, March 7, 2012

Rounding Error?

I'm passing a value from an ASP.net app to an sql stored procedure which stores it in a table.

Problem is if, for example, the value is 2.81 the value is ending up as 2.08999... in my table, but if i do say 6.3 it's fine.

Ive tried having the variable in asp and the field where its stored in sql as a number of types but all with the same result.

Any ideas?

Geoff.You should check the definition and precision of your database column.
Maybe change it from float to money.

Regards
Fredrik