Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2005 Forums
 Transact-SQL (2005)
 update @var=col=new_value

Author  Topic 

laailalalaa
Yak Posting Veteran

57 Posts

Posted - 2010-04-25 : 18:40:23
i have table Account(operationtype,value,date), where operationtype = deposit or withdrawal.
after each operation performed, i want to display the current amount of money in the account.
i already solved this in 2 ways, using a cursor and a select stmnt, which both work fine, but i got stuck when i tried to solve it using an update and now it bugs me that i can't figure it out.

my update is:

DECLARE @amntMoney money
SET @amntMoney = 0
UPDATE Account
SET @amntMoney = value = @amntMoney + (CASE WHEN operationtype = 'deposit' THEN value ELSE -value END)

this would update the 'value' column in the table to display the current amount of money in the account; the problem is that i don't know how or where to place an 'order by date clause', so that the update stmnt takes the records in order, from the first date to the last date in the table.

how can i fix this?

thanks

khtan
In (Som, Ni, Yak)

17689 Posts

Posted - 2010-04-25 : 21:20:51
you can't "update" a variable. You can assign value to it using SET or SELECT.


SELECT @amntMoney = SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END)
FROM Account



KH
[spoiler]Time is always against us[/spoiler]

Go to Top of Page

Vinnie881
Master Smack Fu Yak Hacker

1231 Posts

Posted - 2010-04-25 : 21:48:16
You can update a value using a variable, but keep in mind this method is not supported by sql. The rule of thumb that most people follow to ensure the corerct order is the following.

1. Have a cluster index on the field you want to order by (Should be a ID column though and not a date)
2. Set a anchor variable to that field
3. Don't link any other tables.


DECLARE @amntMoney money, @MyAncher int
SET @amntMoney = 0
UPDATE A
SET
@MYancher = a.CLUSTERIDCOLUMN
,@amntMoney = value = @amntMoney + (CASE WHEN operationtype
= 'deposit' THEN value ELSE -value END)
FROM
Account a


Keep in mind this SHOULD work, it is not guarenteed that it will in future versions, and this is not a supported method to update rows in sql, since they do not guarentee the order it will process. By keeping a clustered index a anchor and no linking tables, it SHOULD always work, but depending on how important your data is, you might not want this method since it's not supported.


Success is 10% Intelligence, 70% Determination, and 22% Stupidity.
\_/ _/ _/\_/ _/\_/ _/ _/- 881
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2010-04-26 : 00:45:48
quote:
Originally posted by Vinnie881

You can update a value using a variable, but keep in mind this method is not supported by sql. The rule of thumb that most people follow to ensure the corerct order is the following.


1. Have a cluster index on the field you want to order by (Should be a ID column though and not a date)
2. Set a anchor variable to that field
3. Don't link any other tables.



DECLARE @amntMoney money, @MyAncher int
SET @amntMoney = 0
UPDATE A
SET
@MYancher = a.CLUSTERIDCOLUMN
,@amntMoney = value = @amntMoney + (CASE WHEN operationtype
= 'deposit' THEN value ELSE -value END)
FROM
Account a


Keep in mind this SHOULD work, it is not guarenteed that it will in future versions, and this is not a supported method to update rows in sql, since they do not guarentee the order it will process. By keeping a clustered index a anchor and no linking tables, it SHOULD always work, but depending on how important your data is, you might not want this method since it's not supported.


Success is 10% Intelligence, 70% Determination, and 22% Stupidity.
\_/ _/ _/\_/ _/\_/ _/ _/- 881


adding to that
4. Add MAXDOP 1 to avoid parallelism
5. Use TABLOCKX hint to lock table from being accessed outside if its available across connections (permament table)
6. DOnt use ORDER BY

as per Jeff Modens article

http://www.sqlservercentral.com/articles/T-SQL/68467/

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/

Go to Top of Page

laailalalaa
Yak Posting Veteran

57 Posts

Posted - 2010-04-26 : 12:05:39
Vinnie881, visakh16.. thanks for your solution, it seems pretty elaborate for my needs (just a basic school project). however, i don't think that's what i need. as u pointed out, the clustered index should be on an ID field, not a datetime.

i'll provide some test data, case i wasn't clear enough:).
(deposit,100,1-1-2010)
(deposit,50,1-3-2010)
(withdraw,70,2-1-2010)
using update @var=column=newvalue i want to change the table in order to display the current amount of money in the account, after every operation, in chronological order:
(deposit,100,1-1-2010)
(deposit,150,1-3-2010)
(withdraw,80,2-1-2010)
so i need to somehow guarantee the order in which the update takes place (order by date).

thank u
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

30421 Posts

Posted - 2010-04-26 : 12:47:10
As yourself discovered you cannot guarantee the order of an UPDATE unless you use a cursor, or is using RBAR.
The UPDATE @variable IS documented in books online and fully supported.
However, it is the order of update that is not guaranteed.

So, if you only need the total this is a perfectly valid syntax because you only need the total (a+b equals b+a right?) and not the intermediate steps.



N 56°04'39.26"
E 12°55'05.63"
Go to Top of Page

laailalalaa
Yak Posting Veteran

57 Posts

Posted - 2010-04-26 : 12:59:06
nope, i needed the intermediate results. but thanks for your reply Peso. however, if anyone else has a different opinion, i'll be around :)
Go to Top of Page

laailalalaa
Yak Posting Veteran

57 Posts

Posted - 2010-04-26 : 13:31:30
if anyone is interested, smn came up with this solution:

http://social.msdn.microsoft.com/Forums/en/transactsql/thread/041ad07f-32b4-45e3-8ca2-035c51059f32

Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2010-04-26 : 23:59:28
quote:
Originally posted by laailalalaa

Vinnie881, visakh16.. thanks for your solution, it seems pretty elaborate for my needs (just a basic school project). however, i don't think that's what i need. as u pointed out, the clustered index should be on an ID field, not a datetime.

i'll provide some test data, case i wasn't clear enough:).
(deposit,100,1-1-2010)
(deposit,50,1-3-2010)
(withdraw,70,2-1-2010)
using update @var=column=newvalue i want to change the table in order to display the current amount of money in the account, after every operation, in chronological order:
(deposit,100,1-1-2010)
(deposit,150,1-3-2010)
(withdraw,80,2-1-2010)
so i need to somehow guarantee the order in which the update takes place (order by date).

thank u



for this requirement isnt below enough


SELECT t.operationtype,t1.Amt,t.date
FROM Table t
CROSS APPLY (SELECT SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END) AS Amt
FROM Table
WHERE date < = t.date
)t1


------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/

Go to Top of Page

laailalalaa
Yak Posting Veteran

57 Posts

Posted - 2010-04-27 : 11:05:47
yes, it's enough. but, as previously mentioned, i had solved the problem in two ways: 1. using a cursor 2. using a select, like u did, but without CROSS APPLY. but i wanted to solve it using update as well, provided that was possible.

but thanks again for your time & suggestions :)

quote:
Originally posted by visakh16

quote:
Originally posted by laailalalaa

Vinnie881, visakh16.. thanks for your solution, it seems pretty elaborate for my needs (just a basic school project). however, i don't think that's what i need. as u pointed out, the clustered index should be on an ID field, not a datetime.

i'll provide some test data, case i wasn't clear enough:).
(deposit,100,1-1-2010)
(deposit,50,1-3-2010)
(withdraw,70,2-1-2010)
using update @var=column=newvalue i want to change the table in order to display the current amount of money in the account, after every operation, in chronological order:
(deposit,100,1-1-2010)
(deposit,150,1-3-2010)
(withdraw,80,2-1-2010)
so i need to somehow guarantee the order in which the update takes place (order by date).

thank u



for this requirement isnt below enough


SELECT t.operationtype,t1.Amt,t.date
FROM Table t
CROSS APPLY (SELECT SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END) AS Amt
FROM Table
WHERE date < = t.date
)t1


------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/



Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2010-04-27 : 11:18:34
then its just a matter of converting above select to update


UPDATE t
SET t.Amt=t1.Amt
FROM Table t
CROSS APPLY (SELECT SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END) AS Amt
FROM Table
WHERE date < = t.date
)t1


------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/

Go to Top of Page

laailalalaa
Yak Posting Veteran

57 Posts

Posted - 2010-04-27 : 11:37:06
i wasn't specific enough in my last post, i meant using update @var=col=new_value

quote:
Originally posted by visakh16

then its just a matter of converting above select to update


UPDATE t
SET t.Amt=t1.Amt
FROM Table t
CROSS APPLY (SELECT SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END) AS Amt
FROM Table
WHERE date < = t.date
)t1


------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/



Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2010-04-27 : 11:45:18
ok. but do you know that this type of 3 part update is not reliable? see last part in link below under I broke it heading

http://www.sqlservercentral.com/articles/T-SQL/68467/

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/

Go to Top of Page

laailalalaa
Yak Posting Veteran

57 Posts

Posted - 2010-04-27 : 11:49:50
i'll read it as soon as i recover my password on that site 8-|

quote:
Originally posted by visakh16

ok. but do you know that this type of 3 part update is not reliable? see last part in link below under I broke it heading

http://www.sqlservercentral.com/articles/T-SQL/68467/

------------------------------------------------------------------------------------------------------
SQL Server MVP
http://visakhm.blogspot.com/



Go to Top of Page

Vinnie881
Master Smack Fu Yak Hacker

1231 Posts

Posted - 2010-04-27 : 23:14:20
A quick hint. If you are decide to use the 3 part update, I normally do the following.

1. Select all my records into a Temporary table using the row_Number field to order properly.

2. I create a clustered index on the row_number field. (You can do this at the time you create your temp table or after, in the example I provided I combined 1 & 2)

3. I use a anchor.

4. I add a Error check column onto my results to verify the order was preserved.


Declare @Tbl table(rowID int Primary Key clustered,Amount money, RunningAmount money,errorCheck bit)

--Just using sysobjects to populate my table for this example
insert into @TBL(RowID,Amount)
Select Row_Number() over (Order by Object_ID) as RowID,System_Type_ID as RandomMoney
from sys.columns
order by RowID

Declare @Anchor int,@RunningTotal money,@IsError Bit,@CurrentRow int

set @CurrentRow = 0

Update a
set @Anchor = a.RowID
,@CurrentRow = @CurrentRow + 1
, @RunningTotal = a.RunningAmount = --Use any logic you want, this just adds when odd and subtracts when even rows
case when abs(a.RowID) %2 = 1 then isnull(@RunningTotal,0) + a.Amount
else isnull(@RunningTotal,0) - a.Amount
end
,@isError = a.errorCheck = case when a.RowID <> @CurrentRow or @IsError = 1 then 1 else 0 end
from
@TBL a


if @IsError = 1
Begin
Select 'THERE WAS A ERROR' as Result
End
else
Begin
Select 'Successful' as Result
end
select * from @Tbl






Create a tmp table along with a clustered index

Success is 10% Intelligence, 70% Determination, and 22% Stupidity.
\_/ _/ _/\_/ _/\_/ _/ _/- 881
Go to Top of Page
   

- Advertisement -