2009-01-10 31 views
17

假设您有表PresentationsEvents。保存演示文稿并包含基本事件信息(例如位置和日期)时,将使用触发器自动创建事件。 (恐怕由于技术原因,不可能将数据保存在一个地方并使用视图。)此外,稍后在演示文稿中更改此信息时,触发器也会将更新复制到事件中,像这样:现在防止触发器的相互递归执行?

CREATE TRIGGER update_presentations 
ON Presentations 
AFTER UPDATE 
AS 
BEGIN 
    UPDATE Events 
    SET Events.Date = Presentations.Date, 
     Events.Location = Presentations.Location 
    FROM Presentations INNER JOIN Events ON Presentations.EventID = Events.ID 
    WHERE Presentations.ID IN (SELECT ID FROM inserted) 
END 

,客户需要它,这样,如果用户发生了改变,在事件的信息,它应该回到呈现为好。出于显而易见的原因,我不能做相反的事情:

CREATE TRIGGER update_events 
ON Events 
AFTER UPDATE 
AS 
BEGIN 
    UPDATE Presentations 
    SET Presentations.Date = Events.Date, 
     Presentations.Location = Events.Location 
    FROM Events INNER JOIN Presentations ON Events.PresentationID = Presentations.ID 
    WHERE Events.ID IN (SELECT ID FROM inserted) 
END 

毕竟,这会导致每个触发器在彼此之后触发。我可以做的是在两个表中添加一列last_edit_by,其中包含用户标识。如果有特殊ID无效填补触发(比方说,通过使实际的人积极的所有用户ID,但脚本负面的用户ID),我可以使用,作为退出条件:

AND last_edit_by >= 0 

这可能会实现,但我想要做的是向SQL服务器表明,在一个事务中,触发器应该只触发一次。有没有办法检查这个?或者也许检查一个表是否已经受到触发器的影响?


回答感谢史蒂夫罗宾斯:

只是包装在IF条件检查trigger_nestlevel()潜在嵌套UPDATE语句。例如:

CREATE TRIGGER update_presentations 
ON Presentations 
AFTER UPDATE 
AS 
BEGIN 
    IF trigger_nestlevel() < 2 
     UPDATE Events 
     SET Events.Date = Presentations.Date, 
      Events.Location = Presentations.Location 
     FROM Presentations INNER JOIN Events ON Presentations.EventID = Events.ID 
     WHERE Presentations.ID IN (SELECT ID FROM inserted) 
END 

请注意,trigger_nestlevel()似乎是基于1的,而不是基于0的。如果您希望每个触发器执行一次,但不是更频繁,只需在两个触发器中检查trigger_nestlevel() < 3

回答

18

我不确定每个事务都会这样做,但是您需要为其他部分启用嵌套触发器吗?如果您在服务器上关闭它们,则触发器不会触发更新表的另一个触发器。

编辑(从评论的答案):您将需要改变触发使用TRIGGER_NESTLEVEL

+0

嵌套触发器是数据库实际上禁用。我的问题是触发A的情况发射B发射A,而不是直接发射A。该设置不妨碍这一点。 – 2009-01-10 10:56:07