Update row entries using Transact-SQL - sql

I have a SQL Server 2014 database called Database.Main which has columns Type and Code.
I need to modify an existing Transact-SQL script to select all the rows that have Type equal to MyObject.Main and change the Code to integer 1000.
How can I do this in Transact-SQL?
BEGIN TRY
BEGIN TRAN Update_Table;
COMMIT;
END TRY
BEGIN CATCH
print 'Error encountered updating entries'
print ERROR_MESSAGE()
rollback;
END CATCH
Answer
Based on the answer from Raul below the solution is this:
BEGIN TRY
BEGIN TRAN Update_Table;
UPDATE Database.Main
SET Code = 1000
WHERE Type = 'MyObject.Main';
COMMIT;
END TRY
BEGIN CATCH
print 'Error encountered updating entries'
print ERROR_MESSAGE()
rollback;
END CATCH

A simple UPDATE command would do?
update table_name
set Code = 1000
where Type = 'MyObject.Main';

Related

Write stored procedure so if one statement fails it should not effect the other?

I have this procedure which basically insert data.
Begin Transaction
Insert into [dbo].Values
(
EQ
)
values
(
#EQ
)
End
--Set #STATUSRet= 'Created'
--Set #ErrorRet= ''
Commit Transaction
End Try
Begin Catch
Set #STATUSRet= 'Failed'
Set #ErrorRet= (Select ERROR_MESSAGE())
Rollback Transaction
End Catch
Now I want to add a piece of code that calls another database server and insert data into the table in that server i.e. remotely. That's ok I will do that but if that fails then that should not effect my current process of inserting the data as I have described above i.e. if the remote data insertion fails it should not effect the prior insert in any way and should return successfully to the calling application behaving like nothing happened.
The default method of controlling transactions is auto-commit:
Any single statement that changes data and executes by itself is
automatically an atomic transaction. Whether the change affects one
row or thousands of rows, it must complete successfully for each row
to be committed. You cannot manually rollback an auto-commit
transaction.
So, if the two inserts are not wrapped in explicit transaction this will be the behavior. If you have more code blocks, then you can use two separate explicit transactions blocks like this:
DECLARE #ExecuteSecondTransaction BIT = 0;
-- local database
BEGIN TRY
BEGIN TRANSACTION;
-- CODE BLOCK GOES HERE
SET #ExecuteSecondTransaction = 1;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION
END;
-- GET ERRORS DETAILS OR THROW ERROR
END CATCH;
-- remote database
IF #ExecuteSecondTransaction = 1
BEGIN
BEGIN TRY
BEGIN TRANSACTION;
-- CODE BLOCK GOES HERE
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION
END;
-- GET ERRORS DETAILS OR THROW ERROR
END CATCH;
END;

Proper syntax for try statement, if previous statement errors, do this

I wanted to use a control-of-flow statement in a stored procedure that says:
begin try
sql_statement
end try
begin try
sql statement
end try
begin catch
print error
end catch
But the documentation on try catch says:
A TRY block must be immediately followed by an associated CATCH block.
Including any other statements between the END TRY and BEGIN CATCH
statements generates a syntax error.
What would the proper syntax for this be in sql:
execute x_sql_statement
if x_sql_statement errors
execute y_sql_statement
else end
The problem in the above if you're beginning a TRY, ending it, and then starting another TRY. The error message is literally telling you the problem here:
A TRY block must be immediately followed by an associated CATCH block
Maybe do something like this...?
DECLARE #Error bit = 0;
BEGIN TRY
execute x_sql_statement;
END TRY
BEGIN CATCH
SET #Error = 1;
execute y_sql_statement;
END CATCH
IF #Error = 0 BEGIN
execute z_sql_statement;
END
But then, why not do...
BEGIN TRY
execute x_sql_statement;
execute z_sql_statement;
END TRY
BEGIN CATCH
execute y_sql_statement;
END CATCH
Unless you don't want statement y to run if z fails?
Typically something like this
begin try
execute x_sql_statement
end try
begin catch
execute y_sql_statement
end catch

Rollback done - yet this error : Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements

I am getting this error in stored procedure.
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
I read through some of the answers and found that if I return without a commit, I get the error. My stored procedure is something like this:
BEGIN TRY
BEGIN
if #id is null
BEGIN
set #id= (SELECT last_sequence_value FROM table_name WHERE sequence_name = 'id') + 1
BEGIN
BEGIN TRANSACTION
-- update SQL statement here
IF ##ROWCOUNT = 0
BEGIN
ROLLBACK TRANSACTION
RAISERROR('There was an error getting unique id in the table.',10,1)
RETURN
END
IF (##ERROR <> 0)
BEGIN
ROLLBACK TRANSACTION
RAISERROR('There was an error updating record to the table',10,1)
RETURN
END
COMMIT TRANSACTION
END
END
else
BEGIN
-- some sql select statements
END
END
END TRY
BEGIN CATCH
-- Raise an error with the details of the exception
RAISERROR(#ErrMsg, #ErrSeverity, 1) WITH SETERROR
END CATCH
From the above code, I am doing a rollback and returning from the stored procedure. Yet when I run this in the perf testing environment, I get the error mentioned earlier.
Kindly help regarding this.
I have fixed it by adding
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION
in the catch block before I raise an error.
Thanks everyone for the wonderful inputs.
I had a user report this same error in code I inherited, but it was caused by a combination of using a transaction and try/catch inside of the sproc along with calling the sproc inside of a VB.Net System.Transactions.TransactionScope block as well. If an error cropped up inside the sproc, the sproc rolled back everything there correctly, but it apparently rolled back the VB.Net transaction as well and created the mismatch. My fix was to remove the transaction code and the the try/catch blocks from the sproc since the VB.Net transaction will rollback all the inserts/updates inside the sproc if the sproc failed or if the other processing done inside the VB.Net transaction block failed as well. Hopefully this will save someone else a day of frustration.
Here you should use try catch blog inside begin transaction. like this
BEGIN
if #id is null
BEGIN
set #id= (SELECT last_sequence_value FROM table_name WHERE sequence_name = 'id') + 1
BEGIN
BEGIN TRANSACTION
BEGIN TRY
-- update SQL statement here
IF ##ROWCOUNT = 0
BEGIN
ROLLBACK TRANSACTION
RAISERROR('There was an error getting unique id in the table.',10,1)
RETURN
END
IF (##ERROR <> 0)
BEGIN
ROLLBACK TRANSACTION
RAISERROR('There was an error updating record to the table',10,1)
RETURN
END
END TRY
BEGIN CATCH
-- Raise an error with the details of the exception
RAISERROR(#ErrMsg, #ErrSeverity, 1) WITH SETERROR
END CATCH
COMMIT TRANSACTION
END
END
else
BEGIN
-- some sql select statements
END
END
First, compare
DECLARE #ErrorVar INT
RAISERROR(N'Message', 16, 1);
IF ##ROWCOUNT <> 0
PRINT 'Rows <> 0'
IF ##ERROR <> 0
PRINT N'Error = ' + CAST(##ERROR AS NVARCHAR(8));
GO
And this
DECLARE #ErrorVar INT,
#Error INT,
#Cnt INT
RAISERROR(N'Message', 16, 1);
SELECT #ERROR = ##ERROR, #Cnt = ##ROWCOUNT
IF #Cnt <> 0
PRINT 'Rows 0'
IF #ERROR <> 0
PRINT N'Error = ' + CAST(##ERROR AS NVARCHAR(8));
GO
https://learn.microsoft.com/en-us/sql/t-sql/functions/error-transact-sql
Because ##ERROR is cleared and reset on each statement executed, check it immediately following the statement being verified, or save it to a local variable that can be checked later. +

Tell SQL Server the error is "handled" in try...catch

I'd like to indicate to SQL Server 2005, in my BEGIN CATCH...END CATCH block that the error is "handled"... That is, clear the error.
Is that possible? Consider this:
begin transaction
begin try
begin transaction
select cast('X' as bit)
commit transaction
end try
begin catch rollback transaction
select error_number(), error_message()
end catch
commit transaction
This results in the following:
(0 row(s) affected)
(No column name) (No column name)
245 Conversion failed when converting the varchar value 'X' to data type bit.
(1 row(s) affected)
Msg 3902, Level 16, State 1, Line 13
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
Thanks.
A.
Not all errors are maskable. You are always supposed to inspect the XACT_STATE() and see if you can continue. Certain errors (1205 deadlock being a typical example) will rollback the transaction and not allow you to continue.
What you describe (a loop which can preserve the work) is ussualy done with the help of a savepoint:
begin transaction
begin try
while #loopcondition
begin
save transaction loop;
begin try
-- process loop element here
end try
begin catch
if xact_state() = -1
begin
-- whole transaction is doomed
rollback;
raiserror ('Aborting', ....);
end
else if xact_state() = 0
begin
-- trasaction was aborted by inner loop
raiserror ('Aborted inside', ....);
end
else if xact_state() = 1
begin
-- this error is recoverable, rollback to the savepoint and continue the loop
rollback loop
end
end catch
-- continue loop here
fetch next from ....
/*
-- batch commit here if batch committing
if #batchsize
begin
commit;
begin transaction
end
*/
end
commit;
end try
begin catch
-- if we get here, we could not handle the error inside the loop and continue
if xact_state() != 0
rollback
raiserror('failed to process', ...)
end catch

a PRINT 'Success' that screw up a begin trans/ begin try commit / end try?

So I just saw a weird behavior
In one script there is something like:
begin transaction
begin try
stuff
stuff
stuff
print 'commit'
commit transaction
end try
begin catch
print 'rollback'
print error_message()
rollback transaction
end catch
thing is when this script in run, I see the print commit message but it does not make the commit and lock the tables/rows/etc
I have to manually run a commit by selecting the line and run it.
but if I do this
begin transaction
begin try
stuff
stuff
stuff
commit transaction
print 'commit'
end try
begin catch
print error_message()
rollback transaction
print 'rollback'
end catch
(swapped the print and the commit)
it work fine.
anyone know why this would happen?
this works fine for me:
--create table t (rowid int) --create one time before running script
begin transaction
begin try
insert into t values (1)
print 'commit'
print XACT_STATE() --should be 1
commit transaction
print XACT_STATE() --should be 0
end try
begin catch
print ERROR_MESSAGE()
rollback transaction
print 'rollback'
end catch
select * from t
output
commit
1
0
rowid
-----------
1
Close your SSMS window, open a new window, and then run your 1st script again, I'll bet you had an open transaction the first time you ran it, so you needed that extra COMMIT.
EDIT after OP comment:
run this exact script in a new connection to each database:
BEGIN TRY create table t (rowid int) END TRY BEGIN CATCH END CATCH
print 'A - XACT_STATE()='+ISNULL(CONVERT(varchar(10),XACT_STATE()),'')+', ##TRANCOUNT='+ISNULL(CONVERT(varchar(10),##TRANCOUNT),'')
begin transaction
begin try
insert into t values (1)
print 'commit'
print 'B - XACT_STATE()='+ISNULL(CONVERT(varchar(10),XACT_STATE()),'')+', ##TRANCOUNT='+ISNULL(CONVERT(varchar(10),##TRANCOUNT),'')
commit transaction
print 'C - XACT_STATE()='+ISNULL(CONVERT(varchar(10),XACT_STATE()),'')+', ##TRANCOUNT='+ISNULL(CONVERT(varchar(10),##TRANCOUNT),'')
end try
begin catch
print ERROR_MESSAGE()
rollback transaction
print 'rollback'
end catch
print 'D - XACT_STATE()='+ISNULL(CONVERT(varchar(10),XACT_STATE()),'')+', ##TRANCOUNT='+ISNULL(CONVERT(varchar(10),##TRANCOUNT),'')
select * from t
you should get this:
A - XACT_STATE()=0, ##TRANCOUNT=0
(1 row(s) affected)
commit
B - XACT_STATE()=1, ##TRANCOUNT=1
C - XACT_STATE()=0, ##TRANCOUNT=0
D - XACT_STATE()=0, ##TRANCOUNT=0
rowid
-----------
1
(1 row(s) affected)