2017-04-05 45 views
3

第一次发帖,请温柔...SQL Server:指定Update Transaction是否来自触发器的选项?

我有一个需要更新一列的表或者更新或插入行(S),因此我创建了一个触发器(AFTER INSERT, UPDATE)时。问题在于它是递归的,因为插入包含更新语句,因此再次触发触发器。

我也尝试了INSERTUPDATE分成两个不同的触发器,但我已经遇到了问题sp_settriggerorder()trigger_nestlevel(),因为在地方有其他触发,由于开箱应用程序的默认值。

我的问题是,有没有办法使用IF子句来说明更新是来自应用程序本身还是我的触发器?大小写,如果它是我的触发器,比我可以轻松地否则,如果它返回,它不会再递归。

CREATE TRIGGER [dbo].[JobCardMetlInsertUpdateItemDesc] 
ON [dbo].[JobCardMetl] AFTER INSERT 
AS 
    BEGIN TRANSACTION [Description] 

    UPDATE JobCardMetl 
    SET JobCardMetl.Description = item.Description 
    FROM JobCardMetl 
    INNER JOIN item ON JobCardMetl.Item = item.item 
    WHERE JobCardMetl.RecordDate = (SELECT MAX(JobCardMetl.RecordDate) 
            FROM JobCardMetl) 

    COMMIT TRANSACTION [Description] 
+0

触发递归(触发直接触发本身)可以在数据库或服务器(?)级别被禁用。当然会影响一切。 – RBarryYoung

回答

3

您的触发器非常可疑:它没有引用INSERTED伪指令。这意味着你的触发器正在更新不受INSERT影响的记录,这总是一个巨大的代码异味。

递归触发器问题的通常解决方案是要小心哪些列正在更新,即。使用UPDATED(),什么行,与自然的业务逻辑应该停止递归(即嵌套触发器应该找什么更新,因为门卫检查不符合)。

最终,您可以使用逻辑大锤:SET CONTEXT_INFOCONTEXT_INFO()。您检查它,设置它并将其清理到触发器中。如果已经设置,则您知道您是从触发器嵌套的。清理部分至关重要。您也不再祈祷其他应用程序的/ dev做同样的,因为只有每一个会话的上下文信息(SQL 2016改进了这个)。

0

您可以检查描述是否仍然不同于您希望更新的描述。如果相同,则不更新。这样你避免了无尽的递归。

另外,对于WHERE条件,您似乎希望将更新限制为当前插入的记录,但为此您可以使用虚拟INSERTED表,其中包含已插入的记录。

最后,似乎矫枉过正,为一个原子语句开始一个新的事务。请注意,触发无论如何都会在触发INSERT语句执行的事务中执行。

因此,采取一切在一起,你可以让你的触发如下(我假设RecordDate唯一标识一个记录 - 它更改为无论是主键):

CREATE TRIGGER [dbo].[JobCardMetlInsertUpdateItemDesc] 
ON [dbo].[JobCardMetl] AFTER INSERT 
AS 
    UPDATE JobCardMetl 
    SET j.Description = item.Description 
    FROM JobCardMetl j 
    INNER JOIN item ON j.Item = item.item 
    INNER JOIN INSERTED i ON i.RecordDate = j.RecordDate 
    WHERE j.Description IS NULL OR j.Description <> item.Description