Understanding nested transaction SQL - sql

I have this code:
begin transaction outside
go
begin transaction inside
go
print 'inside done'
commit transaction inside
update Action set IdUser = 9999999999999
commit transaction outside
This code throws an exception on purpose at "update Action set IdUser = 999...", because of a foreign key problem.
I wish to rollback in case anything wrong occurs. That's why I have an outside transaction. In real world, I have a SQL file with a lot of scripts, and I want to make sure all the scripts maintain in a transaction, so I want to wrap it in an outside transaction.
That code above is not working. It's printing "inside done", and then throws an exception. This print could be a big insertion.
What's going on? How do I solve it?

Just try your query using the below template:
begin tran outside
begin try
begin tran inside
print 'inside done' --Insert\Update\Delete
Update Action set IdSuer = 999999999
END TRY
BEGIN catch
rollback tran inside
rollback tran outside
GOTO FINISH
END catch
commit tran inside
commit tran outside
:FINISH
print 'END'

Related

Stop a stored procedure from further execution once the condition is violated?

I have a following stored procedure and i want to abort it once the number of rows in fact table are not similar to the historical data. So i'm trying to do something like, till now it only sends the email to the users that the data is not same but i want to add an another feature, i.e to abort/stop the SP if the rows difference is more than 5%. But it's not working properly. Can anyone explain where i'm making the mistake? Following is the chunk of stored procedure where i'm making modifications:
SET XACT_ABORT ON;
Begin Try
Begin Transaction;
if (#delta_ok = 0)
set #email_body = #email_body+char(13)+char(10)+'ETL process has been stopped.'
Return
else
set #email_body = #email_body+char(13)+char(10)+'ETL process is copying the data .'
Commit Transaction;
Begin Catch
Rollback Transaction
End Catch
End Try
So my question is that if put "RETURN" inside the "if" statement would it stop the SP? Once the condition is violated? And pass to "ELSE" if the condition isn't fulfilled?
Your syntax is all over the place here. Using some formatting to add clarity will help considerably. Also you have an anti-pattern in your code I call Try/Squelch. You catch an error but then you swallow it and don't tell anybody it happened. When exceptions happen you need to handle them. That means you need to tell the calling program something went wrong, not just silently ingest the details so nobody knows it happened or how to fix it.
Begin Try
Begin Transaction;
if (#delta_ok = 0)
begin
set #email_body = #email_body + char(13) + char(10) + 'ETL process has been stopped.'
Return
end
else
begin
set #email_body = #email_body + char(13) + char(10) + 'ETL process is copying the data .'
Commit Transaction;
end
End Try
Begin Catch
Rollback Transaction
--you really need something here to log/audit and probably tell the calling program something failed.
End Catch

SQL Code Guard and nested transactions rollback?

I have a stored procedure that may be called from a transaction. When there is an exception I want to rollback the transaction (the top-level transaction). I would like to use something like this:
...procedure definition...
BEGIN
BEGIN TRY
--work&logic
END TRY
BEGIN CATCH
-- An error occurred!
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
END
The catch with this is, that the SQL Code Guard reports for this the warning EI020 - ROLLBACK TRANSACTION without BEGIN TRANSACTION. Is there a way to write this properly?

Execute update clause even with errors

I'm doing some script testing and I want to make sure that if the Update Clause I'm testing in this Try Catch :
BEGIN TRY
BEGIN TRAN
UPDATE NAME
SET NAME.ADDBY =
(CASE WHEN NAME.ADDBY = 'CONVERSION' THEN 'CONVERTED'
WHEN NAME.ADDBY = 'CJDOG'THEN 'CJDAREME'
WHEN NAME.ADDBY = 'npalerm' THEN 'REALLYLONGDETAILEDTEXT'
ELSE NAME
END)
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##TRANCOUNT >0
PRINT ERROR_MESSAGE()
ROLLBACK TRAN
END CATCH
PRINT ##TRANCOUNT
fails, that other rows are updated and only the ones that didn't error go through.
Currenty because it is in the TRY CATCH there is a ROLLBACK that makes sure nothing goes through.
But when I try to run just the UPDATE part the errors terminates the whole script, instead of updating those that do not cause an error, in this case npalerm is too long in the case.
Any Ideas?
I know its a long desc I could've just included the Update but for detailed purpose I included it in the Catch.
In order to update the rows individually and catch the errors on each row rather than catching errors on the entire table/view update, you would need to wrap the whole thing in a cursor.
Be aware that cursors are more resource intensive and slower than set-based commands.

why the same try catch block have two different results

I want to rollback all statements in the CATCH block when the error is encountered in the TRY block:
BEGIN TRY
begin transaction
create table t3(a int )
insert into t3 values(1)
insert into t3 values(1,2) --error occur
insert into t3 values(3)
END TRY
BEGIN CATCH
--just take care of rollback
IF ##TRANCOUNT <> 0
BEGIN
PRINT 'in catch,ROLLING BACK';
ROLLBACK
END
END CATCH
go
At first the error is caught since the PRINT in the CATCH block works. However, after several changes back and forth, the error seems not be caught in the CATCH any more since no more printing happens.
Therefore, I open a new query and execute the same thing. This time error can be caught again!!
Sorry about the big images
When you run this code in a tool like management studio, your transaction is mantained for your SPID (assigned to a query window).
So the inconsistent reult issue is because you don't close the transaction on all of your code paths (lets say the rollback dosn't get reached), your transaction is still active the next time you run the script.
If you add IF ##TRANCOUNT <> 0 rollback transaction to the begining of your script you will have a consistent output.
Also notice that the try catch block is not meant to catch errors at statement compile level.
If you replace your error by a division by zero for example (print 1 / 0) the catch will work properly.
In MSDN
The following types of errors are not handled by a CATCH block when they occur at the same level of execution as the TRY…CATCH construct:
Compile errors, such as syntax errors, that prevent a batch from
running.
Errors that occur during statement-level recompilation, such as object name resolution
Errors that occur after compilation because of deferred name resolution.

RAISERROR from Catch Block in TSQL Passed to Calling Batch - Need that Passed to Calling Application

I have been researching the TRY/CATCH block and I am a little stumped on how to pass an error the way I need to do so. From what I have read and if I understand correctly, a RAISERROR in a CATCH block in SQL will be passed to the calling batch OR the calling application. The application is running a stored procedure which has a transaction in it. The transaction is wrapped in a TRY/CATCH block. In the CATCH block, I am raising the error if something in the transaction fails causing it to jump to CATCH. If running the procedure via SSMS, the error shows up fine and the transaction rolls back. However, if the application calls the stored procedure and the same error occurs, the application never knows about the error and thus doesn't now the procedure failed.
First of all, am I understanding correctly how the RAISERROR in CATCH works? If so, how can I get that error raised back to the calling application?
BEGIN TRY
BEGIN TRAN
...............
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
DECLARE #ErrMsg NVARCHAR(4000)
SELECT #ErrMsg = ERROR_MESSAGE()
RAISERROR(#ErrMsg, 16, 1)
END CATCH
I am Running Windows 7, SQL Server 2005
The easiest way to do what your trying to do would be to declare #ErrMsg as an output parameter of your procedure and handle that in your calling application.
You can read up on how RAISEERROR handles it's output here if you wish to continue using it to handle your error outputs. http://msdn.microsoft.com/en-us/library/ms178592.aspx