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 为正,但脚本的用户 ID 为负),我可以将其用作退出条件:

    AND last_edit_by >= 0

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


感谢史蒂夫·罗宾斯(Steve Robbins)的回答:

只需将潜在的嵌套UPDATE语句包装在 IF 条件检查中即可trigger_nestlevel()。例如:

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两个触发器。

4

1 回答 1

19

我不确定是否要按事务执行此操作,但是您是否需要为其他部分打开嵌套触发器?如果您在服务器上将它们关闭,则触发器不会从另一个触发器更新表时触发。

编辑(评论中的答案):您需要更改触发器 A 以使用TRIGGER_NESTLEVEL

于 2009-01-10T10:33:43.443 回答