I have a TSQL script that does a lot of database structure adjustments but it\'s not really safe to just let it go through when something fails.
to make things clear:
You could try something like this... If you are using Try block... The error level 16, (or most of application error), immediately transfers the control to the CATCH block without executing any further statements in the try block...
Begin Transaction
Begin Try
-- Do your Stuff
If (@@RowCount <> 1) -- Error condition
Begin
Raiserror('Error Message',16,1)
End
Commit
End Try
Begin Catch
IF @@Trancount > 0
begin
Rollback Transaction
End
Declare @ErrMsg varchar(4000), @Errseverity int
SELECT @ErrMsg = ERROR_MESSAGE(),
@ErrSeverity = ERROR_SEVERITY()
RAISERROR(@ErrMsg, @ErrSeverity, 1)
End Catch
Hope this helps...
I didn't use the raiseerror solution, because it failed as I didn't have admin permissions. I extended the noexec on/off solution with the transaction handling as follows:
set noexec off
begin transaction
go
<First batch, do something here>
go
if @@error != 0 set noexec on;
<Second batch, do something here>
go
if @@error != 0 set noexec on;
<... etc>
declare @finished bit;
set @finished = 1;
SET noexec off;
IF @finished = 1
BEGIN
PRINT 'Committing changes'
COMMIT TRANSACTION
END
ELSE
BEGIN
PRINT 'Errors occured. Rolling back changes'
ROLLBACK TRANSACTION
END
Apparently the compiler "understands" the @finished variable in the IF, even if there was an error and the execution was disabled. However, the value is set to 1 only if the execution was not disabled. Hence I can nicely commit or rollback the transaction accordingly.
SET XACT_ABORT ON
BEGIN TRAN
-- Batch 1
GO
if @@TRANCOUNT = 0
SET NOEXEC ON;
GO
-- Batch 2
GO
if @@TRANCOUNT = 0
SET NOEXEC ON;
GO
-- Batch 3
GO
if @@TRANCOUNT > 0
COMMIT
GO
Try using RETURN. this will exit the script or procedure immediately and will not execute any of the following statements. You can use this in conjunction with BEGIN, ROLLBACK and COMMIT TRANSACTION statements to undo any data damage:
BEGIN
BEGIN TRANSACTION
<first batch>
IF @@error <> 0
begin
RAISERROR ('first batch failed',16,-1)
ROLLBACK TRANSACTION
RETURN
end
<second batch>
IF @@error <> 0
begin
RAISERROR ('second batch failed',16,-1)
ROLLBACK TRANSACTION
RETURN
end
PRINT 'WIN!'
COMMIT TRANSACTION
END
When the error occurs, the transaction is rolled back automatically, and the current batch is aborted.
Execution continues into the next batch, however. So all the stuff in the batches after the error gets executed. And then when you check for errors later, you try to rollback an already rolled back transaction.
Also, to stop the entire script, not just the current batch, you should use:
raiserror('Error description here', 20, -1) with log
See my answer here for details on that one.
So you need to check for @error
after each batch, I think something like this should work:
BEGIN TRANSACTION
GO
ALTER Stuff
GO
if @@error != 0 raiserror('Script failed', 20, -1) with log
GO
CREATE New Stuff
GO
if @@error != 0 raiserror('Script failed', 20, -1) with log
GO
DROP Old Stuff
GO
if @@error != 0 raiserror('Script failed', 20, -1) with log
GO
PRINT 'No Errors ... Committing changes'
COMMIT TRANSACTION