更新列的 T-SQL 触发器

Dan*_*ana 7 trigger sql-server t-sql

我已经使用 SQL 查询几个星期了,我正在尝试从错误中学习和理解。我有两列的表IsInvisible (bit)ShortName (string)当一个被改变为更新的另一个也如: -如果添加〜于SHORTNAME到组的前面IsInvisible为1,并且如果〜被去除,以将其设置为0 -如果IsInvisible被设置为1 在 ShortName 前面添加 ~ 并在设置为 0 时将其删除。

我试过这样的事情:

ALTER TRIGGER [dbo].[updateInvisibility]
ON [dbo].[table]
AFTER UPDATE
AS
BEGIN

UPDATE t
SET IsInvisible = (CASE WHEN i.ShortName like '~%' THEN 1 ELSE 0 END),
    ShortName = (CASE WHEN i.IsInvisible = 1 AND t.ShortName NOT LIKE '~%'
                 THEN '~' + t.ShortName
                 ELSE t.ShortName
            END)
FROM table t JOIN
     inserted i
     ON t.Id = i.Id;

end
Run Code Online (Sandbox Code Playgroud)

我的问题是,当我更新其中一列或同时更新两列时,没有任何反应,并且出现此错误:

Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32)
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

“允许触发器触发其他人”选项显示“真”。

小智 10

这是问题所在:

  1. 你更新表
  2. 它触发更新触发器: updateInvisibility
  3. 在触发器中,您再次更新表,以便触发updateInvisibility触发器

然后它一直这样做,所以你最终以一种递归的方式多次触发触发器,甚至没有意识到。SQL Server 将允许此调用嵌套深度为 32 级,然后抛出此错误:

超出最大存储过程、函数、触发器或视图嵌套级别(限制 32)

这是很清楚的。

T-SQL 解决方案

纯代码解决方案是检查嵌套级别,如果大于 1 则离开(1 是第一次被更新调用):

IF TRIGGER_NESTLEVEL() > 1 RETURN;
Run Code Online (Sandbox Code Playgroud)

像这样:

ALTER TRIGGER [dbo].[updateInvisibility]
ON [dbo].[table]
AFTER UPDATE
AS
BEGIN
    IF TRIGGER_NESTLEVEL() > 1 RETURN;

    -- Do your work...
END
Run Code Online (Sandbox Code Playgroud)

选择

正如RBarryYoung在评论中指出的那样,您可以首先通过禁用递归触发器来防止此问题。