触发阻止插入SQL Server

时间:2018-12-18 14:41:11

标签: sql sql-server triggers

我有一个要求要根据某些条件防止在插入后使用插入表。当我直接调用insert语句时,它执行完美,没有任何问题。而在将过程用于具有事务范围的插入语句时,却出现此错误

  

ROLLBACK TRANSACTION请求没有相应的BEGIN TRANSACTION。

我的代码:

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

请让我知道是否缺少任何东西

3 个答案:

答案 0 :(得分:2)

删除触发器内的ROLLBACK TRANSACTION,请记住触发器内的DML语句将使用触发触发器的语句的事务上下文,在这种情况下,它将被以下内容覆盖:

 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  

答案 1 :(得分:1)

从触发器中删除ROLLBACK,并引发严重性为11或更高的错误,以便输入存储过程CATCH块。下面的代码还使用简化版本的THROW重新引发触发错误,而不是抛出新错误,并使用EXISTS处理多行插入。

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

答案 2 :(得分:0)

据我了解

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

更新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