Dejan Dozet
Dejan Dozet

Reputation: 1009

SQL Server try catch not working on create, alter table and adding PK constraint

Is this normal or I am missing something? These statements will not produce rollback

BEGIN TRAN
BEGIN TRY
    CREATE TABLE dbo."aCTIONS" ("ID" int  NOT NULL IDENTITY(1,1) )

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Date" datetime

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Name" nvarchar(50) COLLATE Latin1_General_CI_AS

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "ActionID" int;

    ALTER TABLE "dbo"."aCTIONS" 
        ADD CONSTRAINT PK_aCTIONS_ActionID 
            PRIMARY KEY NONCLUSTERED ("ActionID") 

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Notes" nvarchar(255) COLLATE Latin1_General_CI_AS;

    ALTER TABLE "dbo"."aCTIONS" 
        ADD CONSTRAINT DF_aCTIONS_Notes DEFAULT (N'MISLIM') FOR "Notes"

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Consequence_Paid" bit;

    ALTER TABLE "dbo"."aCTIONS" 
        ADD CONSTRAINT DF_aCTIONS_Consequence_Paid DEFAULT ((1)) FOR "Consequence_Paid"

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Reward_Paid" bit

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "username" int

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "time" time(0)

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "DateOnly" date;

    ALTER TABLE "dbo"."aCTIONS" 
        ADD CONSTRAINT DF_aCTIONS_DateOnly DEFAULT (getdate()) FOR "DateOnly"
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN
END CATCH
IF @@TRANCOUNT > 0
    COMMIT TRAN

Note that big space after ...ADD "ActionID" int, there should be NOT NULL, and after that next statement will try to create PK constraint on it. So error will happen there, and that is OK. But somehow I get error shown in SSMS, prior rollback, and transaction stays active sill, but how? why?

Please, note that this is just an output of a scripting procedure that I am building and trying to ensure that if error exists would never create table partially.

Thanks, Dejan

EDIT 1

OK, OK, but what about this animal, this was generated by SSMS itself:

/* Toprevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.Stavke ADD
    dsad nchar(10) NULL
GO
ALTER TABLE dbo.Stavke SET (LOCK_ESCALATION = TABLE)
GO
COMMIT

?

There has to be something more than this, at the end I am looking for the solution how to put it all in a transaction.

Upvotes: 1

Views: 589

Answers (1)

Dejan Dozet
Dejan Dozet

Reputation: 1009

There is a solution for this:

https://dba.stackexchange.com/questions/29544/rollback-group-of-ddl-statements

and more about it:

https://learn.microsoft.com/en-us/sql/t-sql/language-elements/try-catch-transact-sql?view=sql-server-2017

which lead me to this solution:

SET XACT_ABORT ON; 

BEGIN TRAN
BEGIN TRY
    CREATE TABLE dbo."aCTIONS" ("ID" int  NOT NULL IDENTITY(1,1) )

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Date" datetime

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Name" nvarchar(50) COLLATE Latin1_General_CI_AS

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "ActionID" int;

    ALTER TABLE "dbo"."aCTIONS" 
        ADD CONSTRAINT PK_aCTIONS_ActionID 
            PRIMARY KEY NONCLUSTERED ("ActionID") 

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Notes" nvarchar(255) COLLATE Latin1_General_CI_AS;

    ALTER TABLE "dbo"."aCTIONS" 
        ADD CONSTRAINT DF_aCTIONS_Notes DEFAULT (N'MISLIM') FOR "Notes"

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Consequence_Paid" bit;

    ALTER TABLE "dbo"."aCTIONS" 
        ADD CONSTRAINT DF_aCTIONS_Consequence_Paid DEFAULT ((1)) FOR "Consequence_Paid"

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "Reward_Paid" bit

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "username" int

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "time" time(0)

    ALTER TABLE "dbo"."aCTIONS" 
        ADD "DateOnly" date;

    ALTER TABLE "dbo"."aCTIONS" 
        ADD CONSTRAINT DF_aCTIONS_DateOnly DEFAULT (getdate()) FOR "DateOnly"
END TRY
BEGIN CATCH
    IF (XACT_STATE()) = -1  
    BEGIN
        ROLLBACK TRAN
        THROW
    END
END CATCH
IF (XACT_STATE()) = 1  
    COMMIT TRAN

and the table wasn't created because of an error. Pretty cool, isn't it?

Upvotes: 1

Related Questions