简体   繁体   中英

Trigger to block insert into SQL Server

I have a requirement to prevent insert into table using after insert based on certain condition. When I am calling insert statement directly, it is executing perfectly without any problem. Whereas when am using procedure for insert statement with transaction scope, I am getting this error

The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.

My code:

create table test
(
    id int ,
    name varchar(10)
)

create table test1
(
    id int ,
    name varchar(10)
)

ALTER PROCEDURE test_insert 
    @id INT, @name NVARCHAR(10)
AS
BEGIN
    BEGIN TRY
        BEGIN TRANSACTION
            INSERT INTO test1 (id, name) 
            VALUES (@id, @name)

            INSERT INTO test (id, name) 
            VALUES (@id, @name)
       COMMIT
    END TRY
    BEGIN CATCH
        ROLLBACK;

        DECLARE @errormsg NVARCHAR(MAX)

        SELECT @errormsg = ERROR_MESSAGE();
        THROW 500001, @errormsg, 1;  
    END CATCH
end

ALTER TRIGGER TRG_test
ON dbo.test
AFTER INSERT AS
BEGIN
    DECLARE @idNum INT

    SELECT @idNum = id FROM inserted

    IF @idNum = 1
    BEGIN
        RAISERROR('error', 1,1);
        ROLLBACK TRANSACTION
        RETURN  
    END
END

Please let me know if am missing anything

Remove the ROLLBACK TRANSACTION inside the Trigger, remember that DML statements within the trigger will use the transaction context of the statement that fired the trigger, in this case, it would be covered by:

 Your SP ==>

  BEGIN TRANSACTION
      --Fired the trigger and is involved by the same Transaction from the SP
        insert into test1 (id,name) values(@id,@name)  
        insert into test (id,name) values(@id,@name)
       COMMIT  

Remove the ROLLBACK from the trigger and raise and error with severity 11 or higher so that the stored procedure CATCH block is entered. The code below also uses the simplified version of THROW to reraise the trigger error instead of throwing a new one and uses EXISTS to handle multi-row inserts.

alter proc test_insert @id int, @name nvarchar(10)
as
begin
    BEGIN TRY
        BEGIN TRANSACTION
        insert into test1 (id,name) values(@id,@name)
        insert into test (id,name) values(@id,@name)
       COMMIT
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0 ROLLBACK;
        THROW;
    END CATCH
end
GO
alter TRIGGER TRG_test
ON dbo.test
AFTER INSERT AS
BEGIN
    if EXISTS(select 1 from inserted WHERE id = 1)
        begin
        RAISERROR('error', 16,1);
        RETURN  
    end
END
GO

From my understanding,

alter TRIGGER TRG_test
ON dbo.test
instead of insert as --- Trigger type is changed. Trigged before insert
BEGIN
    declare @idNum int
    select @idNum = id from inserted

    if @idNum <> 1 ------ Condition is changed
        begin

        /* Do what you want.*/

        RETURN  
    end
END

update 1:

create table test(
    id int ,
    name varchar(10)
)

create table test11(
    id int ,
    name varchar(10)
)



alter proc test_insert @id int, @name nvarchar(10)
as
begin
    BEGIN TRY
        BEGIN TRANSACTION
        insert into test11(id,name) values(@id,@name)
        insert into test (id,name) values(@id,@name)
       COMMIT
    END TRY
    BEGIN CATCH
        ROLLBACK;
        declare @errormsg nvarchar(max)
        select @errormsg=ERROR_MESSAGE();
        THROW 500001, @errormsg, 1;  
    END CATCH
end

alter TRIGGER TRG_test
ON dbo.test
instead of insert as --- Trigger type is changed. Trigged before insert
BEGIN
    declare @idNum int, @name int
    select @idNum = id, @name=name from inserted

    if @idNum <> 1 ------ Condition is changed
        begin

        insert into test (id,name) values(@idNum,@name)
    end
    else begin

     print 'You insert invalid value 1'

    end
END

test_insert 1, 2 -- error will be arised.

select * from test
select * from test11

test_insert 2, 2 -- insertion is occurs.

select * from test
select * from test11

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM