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.
| 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 moneySET @amntMoney = 0UPDATE AccountSET @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] |
 |
|
|
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 field3. Don't link any other tables.DECLARE @amntMoney money, @MyAncher intSET @amntMoney = 0UPDATE ASET @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 |
 |
|
|
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 field3. Don't link any other tables.DECLARE @amntMoney money, @MyAncher intSET @amntMoney = 0UPDATE ASET @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 that4. Add MAXDOP 1 to avoid parallelism5. Use TABLOCKX hint to lock table from being accessed outside if its available across connections (permament table)6. DOnt use ORDER BYas per Jeff Modens articlehttp://www.sqlservercentral.com/articles/T-SQL/68467/------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/ |
 |
|
|
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 |
 |
|
|
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" |
 |
|
|
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 :) |
 |
|
|
laailalalaa
Yak Posting Veteran
57 Posts |
|
|
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 enoughSELECT t.operationtype,t1.Amt,t.dateFROM Table tCROSS APPLY (SELECT SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END) AS AmtFROM TableWHERE date < = t.date)t1 ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/ |
 |
|
|
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 enoughSELECT t.operationtype,t1.Amt,t.dateFROM Table tCROSS APPLY (SELECT SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END) AS AmtFROM TableWHERE date < = t.date)t1 ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/
|
 |
|
|
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 updateUPDATE tSET t.Amt=t1.AmtFROM Table tCROSS APPLY (SELECT SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END) AS AmtFROM TableWHERE date < = t.date)t1 ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/ |
 |
|
|
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_valuequote: Originally posted by visakh16 then its just a matter of converting above select to updateUPDATE tSET t.Amt=t1.AmtFROM Table tCROSS APPLY (SELECT SUM(CASE WHEN operationtype = 'deposit' THEN value ELSE -value END) AS AmtFROM TableWHERE date < = t.date)t1 ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/
|
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
|
|
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 headinghttp://www.sqlservercentral.com/articles/T-SQL/68467/------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/
|
 |
|
|
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 exampleinsert into @TBL(RowID,Amount)Select Row_Number() over (Order by Object_ID) as RowID,System_Type_ID as RandomMoneyfrom sys.columnsorder by RowIDDeclare @Anchor int,@RunningTotal money,@IsError Bit,@CurrentRow intset @CurrentRow = 0Update aset @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 endfrom @TBL aif @IsError = 1Begin Select 'THERE WAS A ERROR' as ResultEndelseBegin Select 'Successful' as Resultend select * from @Tbl Create a tmp table along with a clustered index Success is 10% Intelligence, 70% Determination, and 22% Stupidity.\_/ _/ _/\_/ _/\_/ _/ _/- 881 |
 |
|
|
|
|
|
|
|