【问题标题】:Trigger on Update on SQL Server table在 SQL Server 表上更新时触发
【发布时间】:2022-01-01 04:16:10
【问题描述】:

我想为 SQL Server 表的特定条件更新一个列值。 我有以下用于创建表的代码

CREATE TABLE [dbo].[EQUIPMENT](
 [ID] [int] IDENTITY(10000,1) NOT NULL,
 [Equipment] [nvarchar](80) NOT NULL,
 [Facility] [nvarchar](40) NULL,
 [EquipmentType] [smallint] NULL,
 [Active] [bit] NOT NULL)

下面是插入和更新语句

INSERT INTO [Equipment] ([Equipment],[Facility],[EquipmentType],[Active]) VALUES ('E02','1029',10,1)
UPDATE [Equipment] Set Active = 0 where [Equipment] = 'E01'

下面是触发脚本

CREATE TRIGGER dbo.ATRG_EquipmentTypeUpdate
ON [dbo].[Equipment]
AFTER INSERT, UPDATE
AS 
BEGIN   
   SET NOCOUNT ON;

   -- update your table, using a set-based approach
   -- from the "Inserted" pseudo table which CAN and WILL
   -- contain multiple rows!
   UPDATE [dbo].[Equipment] 
   SET  EquipmentType  = 15 
   FROM Inserted i
   WHERE [dbo].[Equipment].ID = i.ID
   AND [dbo].[Equipment].EquipmentType = 10
END
GO

当我尝试运行 Insert OR update 语句时,出现以下错误。

Msg 217, Level 16, State 1, Procedure ATRG_EquipmentTypeUpdate1, Line 12 [Batch Start Line 9]
Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).

任何机构可以提供建议吗?表中还有其他三个触发器。 这个,我需要作为临时解决方案,用于解决方法。

【问题讨论】:

  • 为什么不实际解决实际问题,而不是实施(损坏的)解决方法?
  • 因为,并非所有事情都在您的掌控之中:)。正在度假和即将进行演示的人:)。
  • 您的script 本身不会导致该问题。这比你发布的要多。但我建议您将第二个语句添加到您的触发器中 if not exists (select * from inserted where EquipmentType = 10 return; 不会伤害,可能会有所帮助
  • 然后推迟演示...我最不想要的就是演示即将到来,而开发人员不知道自己在做什么“修复”之前出现的问题说演示。
  • 更多解释 - 我注意到您的错误中的名称 ATRG_EquipmentTypeUpdate1 与您的代码不匹配。这意味着问题出在您在表上定义的触发器集合中。当触发器更新定义它的表时,该操作通常会导致所有更新触发器再次执行。您的触发器代码应始终检查行是否已更新(或插入或删除 - 取决于触发器定义的操作)以避免无意义的执行。即使没有行受到影响,触发器也会执行。

标签: sql-server triggers


【解决方案1】:

除非您选择加入Recursive Triggers,否则更新其表的触发器不会再次触发,因此请检查 RECURSIVE TRIGGERS 数据库设置,如果已打开,请将其关闭:

alter database current set recursive_triggers off

或将触发器编码为不执行零行更新,例如

if not exists (select * from inserted) return

【讨论】:

    【解决方案2】:

    您可以使用TRIGGER_NESTLEVEL 来检查递归调用。

    您还应该检查inserted 中是否没有行。

    CREATE TRIGGER dbo.ATRG_EquipmentTypeUpdate
    ON [dbo].[Equipment]
    AFTER INSERT, UPDATE
    AS 
    BEGIN
       SET NOCOUNT ON;
    
       IF TRIGGER_NESTLEVEL(OBJECT_ID('dbo.ATRG_EquipmentTypeUpdate', 'AFTER', 'DML')) > 1
          OR NOT EXISTS (SELECT 1 FROM inserted)
           RETURN;
    
       -- update your table, using a set-based approach
       -- from the "Inserted" pseudo table which CAN and WILL
       -- contain multiple rows!
       UPDATE 
       SET EquipmentType = 15 
       FROM Inserted i
       JOIN [dbo].[Equipment] e ON e.ID = i.ID
         AND e.EquipmentType = 10;
    END
    

    还要注意在更新中使用正确的JOIN 语法。

    【讨论】:

      猜你喜欢
      • 2011-09-07
      • 2012-03-13
      • 2016-11-03
      • 2012-08-01
      • 2020-01-07
      • 1970-01-01
      • 2020-03-24
      • 2011-06-03
      • 1970-01-01
      相关资源
      最近更新 更多