The easiest way to show this is going to be with some sample code. let's firstly , have a set up like you have:
BEGIN TRANSACTION;
DECLARE @SQL nvarchar(MAX);
CREATE TABLE dbo.Table1 (ID int);
--Needs to be dynamic, as CREATE PROC must be in its own batch
SET @SQL = N'
CREATE PROC dbo.Proc1 @i int AS
SELECT ID
FROM dbo.Table1
WHERE ID = @i;';
EXEC sp_executesql @SQL;
--Works fine
INSERT INTO dbo.Table1 (ID)
SELECT 1;
--Fails
INSERT INTO dbo.Table1 (ID)
SELECT 0/0;
COMMIT;
Now, this will have errored, however, if we try this:
SELECT *
FROM dbo.Table1;
You'll notice this works, and returns data. The following statements also don't return any error:
EXEC dbo.Proc1 @i = 1;
GO
--Both work
DROP PROC dbo.Proc1;
DROP TABLE dbo.Table1;
None of the other statements were rolled backed on the divide by zero error, which isn't what you're after. Like I said in the comments, you need to use a TRY...CATCH
; thus your batch would look something like:
BEGIN TRY
BEGIN TRANSACTION Migration;
DECLARE @SQL nvarchar(MAX);
CREATE TABLE dbo.Table1 (ID int);
--Needs to be dynamic, as CREATE PROC must be in its own batch
SET @SQL = N'
CREATE PROC dbo.Proc1 @i int AS
SELECT ID
FROM dbo.Table1
WHERE ID = @i;';
EXEC sp_executesql @SQL;
--Works fine
INSERT INTO dbo.Table1 (ID)
SELECT 1;
--Fails
INSERT INTO dbo.Table1 (ID)
SELECT 0/0;
COMMIT;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION Migration;
END CATCH
Now, if we try any of the above statements, they will all fail:
--Doesn't work
SELECT *
FROM dbo.Table1;
GO
--Doesn't work
EXEC dbo.Proc1 @i = 1;
GO
--Deosn't work
DROP PROC dbo.Proc1;
DROP TABLE dbo.Table1;
GO
Like i say in the above comments, this means that the SELECT
, EXEC
and DROP
statements all fail, as the objects don't exist.