Error with uncommitted transaction - sql

I have the following query that I ran in SQL Server Management Studio:
BEGIN TRANSACTION [Tran1]
BEGIN TRY
UPDATE SomeTable
SET value = 0
WHERE username = 'test'
OR [PR_RequestDate] < DATEADD(day, -2, GETDATE())
INSERT INTO SomeTable (username, value)
VALUES('test', 'test')
COMMIT TRANSACTION [Tran1]
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION [Tran1]
END CATCH
GO
After executing it every other query that I try to run on the same table runs forever, and when I try to exist SQL Server Management Studio, I get a warning that there are uncommitted transactions.
What exactly is wrong with my query and how should I fix it?

Typos will be caught immediately,further as per Ivan suggestionmyou are not showing us entire info.You are getting uncommitted transactions error due to error in update or insert and the entire query trying to rollback..You can do the follow to get total message and trancount,,
set xact_abort on--to rollback entire batch,rollback in catch is redundant
begin try
begin tran
commit
end try
begin catch
select ##trancount--gives me number of open transactions
select error_message()
rollback tran
end catch

Related

SQL Server Transactions - how to use them [duplicate]

We have client app that is running some SQL on a SQL Server 2005 such as the following:
BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;
It is sent by one long string command.
If one of the inserts fail, or any part of the command fails, does SQL Server roll back the transaction? If it does not rollback, do I have to send a second command to roll it back?
I can give specifics about the api and language I'm using, but I would think SQL Server should respond the same for any language.
You can put set xact_abort on before your transaction to make sure sql rolls back automatically in case of error.
You are correct in that the entire transaction will be rolled back. You should issue the command to roll it back.
You can wrap this in a TRY CATCH block as follows
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN --RollBack in case of Error
-- <EDIT>: From SQL2008 on, you must raise error messages as follows:
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
-- </EDIT>
END CATCH
Here the code with getting the error message working with MSSQL Server 2016:
BEGIN TRY
BEGIN TRANSACTION
-- Do your stuff that might fail here
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
DECLARE #ErrorSeverity INT = ERROR_SEVERITY()
DECLARE #ErrorState INT = ERROR_STATE()
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
From MDSN article, Controlling Transactions (Database Engine).
If a run-time statement error (such as a constraint violation) occurs in a batch, the default behavior in the Database Engine is to roll back only the statement that generated the error. You can change this behavior using the SET XACT_ABORT statement. After SET XACT_ABORT ON is executed, any run-time statement error causes an automatic rollback of the current transaction. Compile errors, such as syntax errors, are not affected by SET XACT_ABORT. For more information, see SET XACT_ABORT (Transact-SQL).
In your case it will rollback the complete transaction when any of inserts fail.
If one of the inserts fail, or any part of the command fails, does SQL server roll back the transaction?
No, it does not.
If it does not rollback, do I have to send a second command to roll it back?
Sure, you should issue ROLLBACK instead of COMMIT.
If you want to decide whether to commit or rollback the transaction, you should remove the COMMIT sentence out of the statement, check the results of the inserts and then issue either COMMIT or ROLLBACK depending on the results of the check.

Is rollback required in SQL Server when transaction failed in commit tran statement

I am working in some existing application using SQL Server 2014 in the backend. I find that the pattern to commit the transaction is like
USE AdventureWorks;
GO
BEGIN TRANSACTION;
GO
DELETE FROM HumanResources.JobCandidate WHERE JobCandidateID = 10;
DELETE FROM HumanResources.JobCandidate WHERE JobCandidateID = 11;
DELETE FROM HumanResources.JobCandidate WHERE JobCandidateID = 12;
GO
COMMIT TRANSACTION;
GO
I am wondering if the query failed in commit transaction statement, do i need to have the rollback statement there?
according to this question Can a COMMIT statement (in SQL) ever fail? How?, the commit tran can fail, but do I have to roll that back since the transaction hasn't been commit successfully. Would SQL server roll that back automatically when the connection is closed?
Please point me to the documentation in MSDN or wherever you got the information.
I believe it will, after the connection is closed. You should not count on this, there are many factors to consider including connection pooling. I suggest you look into SET XACT_ABORT ON and / or using a try catch block.
The way that I use transactions:
Begin Try
Begin Tran
-- do some work here...
Commit Tran
End Try
Begin Catch
If ( ##TranCount > 0 )
Rollback Tran
End Catch
doing your transaction commit/rollbacks in a try/catch is probably a best practice.
if, however you want your code to automatically rollback all of the statements in the transaction you need to add the "set xact_abort on" statement somewhere before the begin trans statement. xact_abort automatically rolls back all of the statements in a transaction if any of them fail. to understand the effect of xact_abort, execute the following code. set xact_abort on and off and observe the contents of the table. the first statement of the batch in the sample will always fail because of a primary key violation.
use tempdb
go
if exists (select * from sys.tables where name='t') drop table t
go
create table t (id int not null primary key)
go
insert t values(1)
go
set xact_abort on
begin transaction
insert t values(1)
insert t values(2)
commit transaction
go
select * from t
You can use try...catch like the below.
BEGIN TRY
DELETE
FROM HumanResources.JobCandidate
WHERE JobCandidateID = 10;
DELETE
FROM HumanResources.JobCandidate
WHERE JobCandidateID = 11;
DELETE
FROM HumanResources.JobCandidate
WHERE JobCandidateID = 12;
COMMIT;
END TRY
BEGIN CATCH
ROLLBACK
SELECT Db_name()
,CONVERT(NVARCHAR(15), Error_number())
,CONVERT(NVARCHAR(10), Error_line())
,Error_message()
END CATCH

SQL Transactions with Commit and Rollback

Can someone tell me if I am correct in understanding the use of START TRANSACTION and COMMIT or ROLLBACK.
If I want to update a table but want the ability to UNDO my update in case of an error would this code be the proper way to go about it?
START TRANSACTION;
update ar
set doc_no = gltrans.reference
from plxx.dbo.ar
inner join plxx.dbo.gltrans on gltrans.LNKUNIQUE = ar.UNIQUE_CD
where gltrans.LNKUNIQUE = ar.UNIQUE_CD
and ar.DOC_NO <> gltrans.REFERENCE
COMMIT;
Here is a pattern that I use for rolling back a transaction on error in a sql statement:
https://web.archive.org/web/20211020150034/http://www.4guysfromrolla.com/webtech/041906-1.shtml
BEGIN TRY
BEGIN TRANSACTION -- Start the transaction
update ar
set doc_no = gltrans.reference
from plxx.dbo.ar
inner join plxx.dbo.gltrans on gltrans.LNKUNIQUE = ar.UNIQUE_CD
where gltrans.LNKUNIQUE = ar.UNIQUE_CD
and ar.DOC_NO <> gltrans.REFERENCE
-- If we reach here, success!
COMMIT
END TRY
BEGIN CATCH
-- Whoops, there was an error
IF ##TRANCOUNT > 0
ROLLBACK
-- Raise an error with the details of the exception
DECLARE #ErrMsg nvarchar(4000), #ErrSeverity int
SELECT #ErrMsg = ERROR_MESSAGE(),
#ErrSeverity = ERROR_SEVERITY()
RAISERROR(#ErrMsg, #ErrSeverity, 1)
END CATCH
Yes, if you have an error occur after starting a transaction & before the commit statement anything within that statement will be rolled back. You can also include Try/Catch statements if you want some additional functionality around error management, for example logging of the failure.
Use BEGIN TRANSACTION instead of using START TRANSACTION. after executing the UPDATE command, you can roll it back by using ROLLBACK then to confirm the transaction use COMMIT.

TSQL error checking code not working

I'm trying to add an alert to my log for a running insert of a view into a table when there is an error executing the query in the view. When I run the view alone, I get an invalid input into SUBSTRING (the exact wording of the error I can't remember). When I run it as part of my view -> table stored procedure, the error is ignored, then I have to go digging for the offending line and make an exception in the view's code to omit that line from the results (I know, it sounds kludge-y, but I'm doing data reduction on huge web-log files from a specialized webapp), but I digress.
I've tried two different methods for trying to catch the error and neither are triggered in such a way to insert the row indicating an error in my execution result table (refresh_results). I think I may be missing some fundamental - perhaps the errors are being encapsulated in come way. If I can't detect the error, the only way to notice an error is if someone notices the number of entries into the table is low for a given period of time.
SELECT #TransactionName = 'tname';
BEGIN TRANSACTION #TransactionName;
BEGIN TRY
print 'tname ***In Try***';
if exists (select name from sysobjects where name='tablename')
begin
drop table tablename;
end
select * into tablename
from opendatasource('SQLNCLI', 'Data Source=DATABASE;UID=####;password=####').dbo.viewname;
COMMIT TRANSACTION #TransactionName;
END TRY
BEGIN CATCH
print 'tablename ***ERROR - check for SUBSTRING***';
begin transaction
set #result_table = 'tablename ***ERROR - check for SUBSTRING***'
select #result_time = getdate(),
#result_rows = count(logtime)
from tablename
insert INTO [dbo].[refresh_results] (result_time, result_table, result_rows)
values (#result_time, #result_table, #result_rows);
commit transaction
ROLLBACK TRANSACTION #TransactionName;
END CATCH
or
if exists (select name from sysobjects where name='tablename')
begin
drop table tablename;
end
select * into tablename
from opendatasource('SQLNCLI', 'Data Source=DATABASE;UID=####;password=####').dbo.viewname;
print '##error'
print ##error
if ##error <> 0
Begin
print 'tablename ***ERROR - check for SUBSTRING***';
set #result_table = 'tablename ***ERROR - check for SUBSTRING***'
select #result_time = getdate(),
#result_rows = count(logtime)
from tablename
insert INTO [dbo].[refresh_results] (result_time, result_table, result_rows)
values (#result_time, #result_table, #result_rows);
End
Your nested transactions aren't doing what you think. You are rolling back the error you thought you stored. Roll back the initial transaction and then, if you feel the need, start a new transaction for logging the error.
See here.
You have two seperate problems
In your first example you are running transactions that do the following:
BEGIN TRAN
...error...
BEGIN TRAN
...log error...
COMMIT TRAN
ROLLBACK TRAN
The inner transaction is rolled back with the outer transaction. Maybe try:
BEGIN TRAN
...error...
ROLLBACK TRAN
BEGIN TRAN
...log error...
ROLLBACK TRAN
The second example you are using ##ERROR. As I understand it as soon as you run something ##ERROR is replaced. That something I think includes the print statement.
If you change it to something like:
DECLARE #Error INT
select * into tablename
from opendatasource('SQLNCLI', 'Data Source=DATA3;UID=;password=').dbo.viewname;
SET #Error = ##ERROR
print '##error'
print #Error
if #Error <> 0
...log the error
The advantage of the TRY CATCH is that if you have an error it will catch it. The ##ERROR method works 100% but it only works on the last line run. so if you have an error with DROP TABLE tablename ##ERROR won't get it (unless you add another check)
Ok, so I had to use a helper procedure to add a log entry. I think what was going on is that the rollback was also rolling back the log entry.
This is what I had to do:
DECLARE #myError tinyint;
BEGIN TRY
BEGIN TRANSACTION;
if exists (select name from sys.sysobjects where name='table_name')
begin
drop table table_name
end
select * into table_name
from opendatasource('SQLNCLI', 'Data Source=###;UID=###;password=###').view_Table
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
set #myError = 1
ROLLBACK TRANSACTION;
END CATCH
if #myError <> 0
begin
exec dbo.table error
end
ELSE
EXEC exec dbo.table normal row

SQL Server - transactions roll back on error?

We have client app that is running some SQL on a SQL Server 2005 such as the following:
BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;
It is sent by one long string command.
If one of the inserts fail, or any part of the command fails, does SQL Server roll back the transaction? If it does not rollback, do I have to send a second command to roll it back?
I can give specifics about the api and language I'm using, but I would think SQL Server should respond the same for any language.
You can put set xact_abort on before your transaction to make sure sql rolls back automatically in case of error.
You are correct in that the entire transaction will be rolled back. You should issue the command to roll it back.
You can wrap this in a TRY CATCH block as follows
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN --RollBack in case of Error
-- <EDIT>: From SQL2008 on, you must raise error messages as follows:
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
-- </EDIT>
END CATCH
Here the code with getting the error message working with MSSQL Server 2016:
BEGIN TRY
BEGIN TRANSACTION
-- Do your stuff that might fail here
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
DECLARE #ErrorSeverity INT = ERROR_SEVERITY()
DECLARE #ErrorState INT = ERROR_STATE()
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
From MDSN article, Controlling Transactions (Database Engine).
If a run-time statement error (such as a constraint violation) occurs in a batch, the default behavior in the Database Engine is to roll back only the statement that generated the error. You can change this behavior using the SET XACT_ABORT statement. After SET XACT_ABORT ON is executed, any run-time statement error causes an automatic rollback of the current transaction. Compile errors, such as syntax errors, are not affected by SET XACT_ABORT. For more information, see SET XACT_ABORT (Transact-SQL).
In your case it will rollback the complete transaction when any of inserts fail.
If one of the inserts fail, or any part of the command fails, does SQL server roll back the transaction?
No, it does not.
If it does not rollback, do I have to send a second command to roll it back?
Sure, you should issue ROLLBACK instead of COMMIT.
If you want to decide whether to commit or rollback the transaction, you should remove the COMMIT sentence out of the statement, check the results of the inserts and then issue either COMMIT or ROLLBACK depending on the results of the check.