Ignoring the setup bit, your script:
- starts a transaction
- does a delete
- does an insert
- runs a bit of code that generates an error
- does a
COMMIT
So, of course those initial changes have applied. You can set XACT_ABORT
on which will cause any batch that generates an error to rollback the transaction, but you still need to be very careful:
create table T(ID int)
go
set xact_abort on
go
begin transaction
go
insert into T(ID) values (1)
go
alter table T add ID int null
go
insert into T(ID) values (2)
go
commit
go
select * from T
Produces these messages:
(1 row(s) affected)
Msg 2705, Level 16, State 4, Line 1
Column names in each table must be unique. Column name 'ID' in table 'T'
is specified more than once.
(1 row(s) affected)
Msg 3902, Level 16, State 1, Line 1
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
(1 row(s) affected)
And still has a row containing 2
in the table. Why? Because the error terminated the transaction with a rollback, but then the next batch (containing insert into T(ID) values (2)
) was run without an explicit transaction existing. There's not much help you can get when it comes to error handling across batches, except some manual steps, e.g.:
create table T(ID int)
go
set xact_abort on
go
begin transaction
go
insert into T(ID) values (1)
go
alter table T add ID int null
go
if @@TRANCOUNT = 0 goto errored
insert into T(ID) values (2)
errored:
go
if @@TRANCOUNT = 0 goto errored
commit
errored:
go
select * from T
And you'll have to do the same in every batch that might follow one containing errors.