August 20, 2004 at 12:09 pm
I have a stored procedure that archives data from a table into a history table. The steps are as follows.
Begin Tran A1
Step One:
Inserts into Table1_HIST (.....) --insert into the history table
Select .... from Table1 where field = 'something'
Step Two:
Delete from Table1 where field = 'something' --delete from the original tables all the records moved to the history table.
If @@Error <> 0 then rollback Tran A1 else commit Tran A1
Is there a way I can make sure that the Insert statement will run and complete before the delete statement runs? If I use 'GO', I get errors in the stored proc. Could the delete statement execute before the insert statement runs causing some records to be deleted before inserted into the _HIST table??
Thanks in advance!!!!
August 21, 2004 at 3:25 am
The steps should execute in the order of statements, so (timewise) there is no need to worry that records are deleted before the insertion takes place.
But transaction-wise, another problem may occur. If the first statement (the insert) fails, and the other statement (delete) succeeds, you will not automatically get a rollback. (Unless the setting "XACT_ABORT" is on.)
I normally check after each (significant) statement:
------------------
begin Tran A1
insert into Table1_Hist (...)
if @@error 0 goto proc_exit
select ... from Table1 where field = 'something'
delete from Table1 where field = 'something'
proc_exit:
if @@error 0 rollback Tran A1
else commit Tran A1
------------------
I'm sure there are alternative approaches to do this, and I would be interested in hearing them.
August 21, 2004 at 2:16 pm
Set XACT is brute force, but in many cases perfectly acceptable. Checking @@Error gives you some flexibility, no all errors should cause it to fail.
The downside to the technique you're using is that there is a potential for a record to get changed between the time you archive and delete. In the worst case you would delete a record without archiving it. A better approach is to capture your history in a delete trigger, insuring that deletes can never be missed.
August 22, 2004 at 4:29 pm
My suggestions in "bold" typeface...
Step One:
DECLARE A VARIABLE AS AN "INT"
SELECT THE MAX ID FROM THE SOURCE TABLE INTO THE VARIABLE
BEGIN TRAN
Inserts into Table1_HIST (.....) --insert into the history table
Select .... from Table1 WITH (NOLOCK) where field = 'something'
WHERE THE ID IS <= TO THE MAX ID VARIABLE
IF @@ERROR <> 0
BEGIN
PRINT "SOMETHING WENT WRONG WITH THE "INSERT" PORTION OF THE TRASFER"
ROLLBACK
RETURN
END
Step Two:
Delete from Table1 where field = 'something' --delete from the original tables all the records moved to the history table.
WHERE THE ID IS <= TO THE MAX ID VARIABLE
IF @@ERROR <> 0
BEGIN
PRINT "SOMETHING WENT WRONG WITH THE "DELETE" PORTION OF THE TRASFER"
ROLLBACK
RETURN
END
COMMIT
Be advised that if table1 is a transactional input table associated with a GUI, the GUI may be frozen while the DELETE segment is running until COMMIT releases the tables or a ROLLBACK completes. The WITH (NOLOCK) keeps the table from being locked during the SELECT and also allows the INSERT/SELECT to function even if someone does have the table locked (allows "dirty reads").
The purpose of the Max ID variable is to keep from deleting records that may have been inserted to the table during the INSERT/SELECT transfer.
--Jeff Moden
Change is inevitable... Change for the better is not.
August 23, 2004 at 8:42 am
Thanks for your responses - it gave me alot to think about.
The records in the table that I'm archiving won't be changed while this procedure is running. My main concern is that I'll delete records before they are inserted into the history table. Some tables in the stored procedure won't be deleted from the table but updated with a new value that is a parameter passed into the stored proc. So, I also worry about the records being udpated before inserted into the history table. So, since the steps execute in the order of statements, I won't need to worry about that right!!???
Thanks for your help!!!
August 25, 2004 at 8:24 am
One quick question on the transactions (I'm a newbie), if I do the following:
begin tran A1
insert into table_hist(.....) select ... from tableA where something = 'something'
if @@error <> 0 goto procexit
delete from tableA where something = 'something'
procexit:
if @@error <> 0 goto procexit rollback tran
else
commit TranA1
Will procexit always execute even if I don't call goto procexit?? I want to make sure that the transaction commits.
Thanks, Jill
August 25, 2004 at 12:33 pm
You need to wrap a begin and end around the "then" part of the if statement and put the goto after the rollback . However, the safest method of nesting transactions:
use named save points
BEGIN TRAN
SAVE TRAN xyz
...program logic...
IF @errcondition <> 0 ROLLBACK TRAN xyz
COMMIT TRAN
...this will ensure your transaction nesting level is always correct.
Viewing 7 posts - 1 through 6 (of 6 total)
You must be logged in to reply to this topic. Login to reply