I have a transaction and two tables where i am inserting some data, can I do partial commits in SQL server
BEGIN TRANSACTION tran1
BEGIN TRY
--Insert into Table1
--Insert into Table2
COMMIT TRANSACTION tran1
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION tran1
END CATCH
Above code will rollback both tables data, is there a way we can commit table 1 if there is no error on table 1 insert but rollback table 2 if there is any error occurred.
The answer is yes, although transactions are indeed atomic you could use a savepoint. So in your case, the code could look like this (untested):
BEGIN TRY
BEGIN TRANSACTION
--Insert into Table1
-- savepoint
SAVE TRANSACTION tran1
--Insert into Table2
-- commit the whole transaction
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- rollback to savepoint
IF ##TRANCOUNT > 0 ROLLBACK TRANSACTION tran1
END CATCH
You may have to adjust insertion order.
Nope, you can't.
A transaction is atomic. That is all of the steps are performed as one, commited together, or rolled back.
If you put both inserts into a single transaction, you can't commit to one table.
You can use different transactions if possible.
Related
I have anonymous block
BEGIN
BEGIN TRANSACTION tran1
-- insert query into table
-- insert query into another table
IF 1=2 -- false condition
BEGIN
ROLLBACK TRANSACTION tran1;
END
END
This transactions commits successfully. Then I change IF condition to be true (1=1) and also change transaction name to tran2, so now anonymous block is:
BEGIN
BEGIN TRANSACTION tran2
-- insert query into table
-- insert query into another table
IF 1=1 -- true condition
BEGIN
ROLLBACK TRANSACTION tran2;
END
END
When trying run this block, it returns "query completed with errors" with message:
Cannot roll back tran2. No transaction or savepoint of that name was found.
(also transaction not rollbacks and inserts are performed).
So, why appears that message when there is definitely transaction with name: "tran2" ?
I created an adhoc which has lots of delete/insert action.
For data integrity, I would like to rollback all if any action goes wrong.
The following is the pseudo code:
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO New_Table VALUES(......)
DELETE FROM Old_Table
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
Is there any performance issue here? I will use this logic about 10 times for insert/delete data in this adhoc.
I have come across the following T-SQL:
...
COMMIT TRANSACTION
END TRANSACTION
BEGIN TRANSACTION;
...
What is the difference between COMMIT and END transaction in this case?
END TRANSACTION doesn't exists in SQL Server T-SQL.
The only transaction commands available are BEGIN TRANSACTION, with an optional name, plus COMMIT and ROLLBACK, also with optional name.
END TRANSACTION will give you a syntax error.
I have code like below, now I need to commit only inner transactions and outer transaction may commit or roll-back. How to handle it?
BEGIN TRY
BEGIN TRANSACTION
INSERT TABLE T1 (1,2,3)
----
----
----
IF t1 > 10
BEGIN
BEGIN TRANSACTION
INSERT INTO ERROR_LOG (XX)
COMMIT
return 1
END
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
END CATCH
Only when t1 > 10 then transaction should commit the error log and terminates program
If you're hoping to store some results into ERROR_LOG and rollback other changes, the inner transaction is not going to do that, since in SQL Server the outer transaction will rollback everything.
Here's some testing & explanation done by Paul Randal: http://www.sqlskills.com/blogs/paul/a-sql-server-dba-myth-a-day-2630-nested-transactions-are-real/
One way to get around of this limitation is to use table variable for the logging, since it will not be rolled back, and then insert the results into the log after doing the rollback.
--Drop Table Tab1
Begin Transaction TR1;
Save Transaction TR1;
Create Table Tab1(f1 decimal(10,0));
Begin Transaction TR2
Save Transaction TR2
insert into Tab1 values(1);
Begin Transaction TR3;
Save Transaction TR3;
insert into Tab1 values(2);
Begin Try
insert into Tab1 values('OK');
Commit Transaction TR3;
END TRY
BEGIN Catch
print 'catch'
RollBack Transaction TR3;
End Catch
insert into Tab1 values(3);
Commit Transaction TR2
insert into Tab1 values(4);
Commit Transaction TR1;
--Commit Transaction;
select * from Tab1;
Drop Table Tab1
Select ##TRANCount
Error Occures :
Msg 3931, Level 16, State 1, Line 17
The current transaction cannot be committed and cannot be rolled back to a savepoint. Roll back the entire transaction.
How to handle this.
When certain type of errors get raised you cannot rollback to a save point. See Martin Smith's answer to Rollback transaction to savepoint on failing ALTER TABLE … ADD CONSTRAINT. The way you detect this is to test Xact_state().
However your problem is somewhat different because you're also trying to use nested transactions. Nested transactions don't really work in SQL as we would expect them to.
You can only name the outermost transaction. See Transactions (Database Engine)
For example this fails with Cannot roll back TR2. No transaction or savepoint of that name was found.
BEGIN TRANSACTION TR1;
BEGIN TRANSACTION TR2
ROLLBACK TRANSACTION TR2
COMMIT Transaction TR1
From Nesting Transactions
Committing inner transactions is ignored by the SQL Server Database Engine
It is not legal for the transaction_name parameter of a ROLLBACK TRANSACTION statement to refer to the inner transactions of a set of named nested transactions. transaction_name can refer only to the transaction name of the outermost transaction
Paul S. Randal explores this further in A SQL Server DBA myth a day: (26/30) nested transactions are real
The best you can do is use Save points instead and check the Xact_state in your catch and at the end.
BEGIN TRANSACTION tr1;
SAVE TRANSACTION tr2;
CREATE TABLE tab1
(
f1 DECIMAL(10, 0)
);
SAVE TRANSACTION tr3
INSERT INTO tab1
VALUES (1);
SAVE TRANSACTION tr4;
INSERT INTO tab1
VALUES (2);
BEGIN try
-- change the order of the follwoing two lines around to see the difference
INSERT INTO tab1 VALUES (1 / 0); --Results in a rollback to savepoint
INSERT INTO tab1 VALUES ('OK'); --Results in a complete rollback
COMMIT TRANSACTION tr4;
END try
BEGIN catch
IF Xact_state() = -1
BEGIN
PRINT 'rollback transaction no other work can be done'
ROLLBACK TRANSACTION;
END
ELSE
BEGIN
PRINT 'rollback to savepoint'
ROLLBACK TRANSACTION tr4
END
END catch
IF Xact_state() > 0
BEGIN
INSERT INTO tab1
VALUES (3);
INSERT INTO tab1
VALUES (4);
COMMIT TRANSACTION tr1;
SELECT *
FROM tab1;
DROP TABLE tab1
END