在这个接受的答案的末尾有一个声明,如果在“For Delete”触发器中发生错误,删除操作将被回滚,因为它是隐式事务的一部分。
但是,这里有一个示例显示即使引发错误,已删除的行仍然被删除:
create table T1 ( i1 int );
go
create trigger T1_ForDelete on T1
for delete
as
raiserror('Raised 16', 16, 1);
raiserror('Raised 18', 18, 1);
raiserror('Raised #2 16', 16, 255);
raiserror('Raised #2 18', 18, 255);
go
insert into T1 (i1) values (1);
set xact_abort on; -- makes no difference
delete from T1;
输出(顺序更改):
Msg 50000, Level 16, State 1, Procedure T1_ForDelete, Line 4
Raised 16
Msg 50000, Level 16, State 255, Procedure T1_ForDelete, Line 6
Raised #2 16
(1 row(s) affected)
Msg 50000, Level 18, State 1, Procedure T1_ForDelete, Line 5
Raised 18
Msg 50000, Level 18, State 255, Procedure T1_ForDelete, Line 7
Raised #2 18
然后
select * from T1; -- Returns no records
这是预期的行为还是有办法防止删除错误(例如不同的严重性/状态)?
我不能使用“代替删除”,因为使用了“删除级联”。 创建触发器(MSDN),搜索“For INSTEAD OF”
为了使它像您在上面编码的那样工作,您需要在您的之后进行回滚,
RAISERROR
或者,正如评论正确指出的那样,包装在 TRY/CATCH 中。就其本身而言,它不会被视为与实际语句或批处理终止错误相同。例如,这将按您期望的方式工作:
在上面的代码中,触发器会出错,并导致删除(外部)事务回滚。RAISERROR 本身只是真正转移控制和/或向堆栈发送消息(可以这么说)
BOL 描述了这种行为:
因此,在 TRY 块范围之外的 RAISERROR 只会将错误返回给调用者,并且无论您定义的严重性如何,都不会被视为语句终止错误。