SQL Server:指定Update Transaction是否来自触发器的选项?

时间:2017-04-05 19:07:15

标签: sql-server database-trigger

首先发帖,请温柔......

当表格更新或插入行时,我需要更新一列,因此我创建了一个触发器(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]

2 个答案:

答案 0 :(得分:3)

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

递归触发器问题的通常解决方案是要小心哪些列正在更新,即。使用UPDATED(),以及哪些行和自然业务逻辑应该停止递归(即嵌套触发器应该找不到任何更新,因为防护检查不符合条件)。

最终你可以使用逻辑大锤:SET CONTEXT_INFOCONTEXT_INFO()。你检查它,设置它并在触发器中清理它。如果已设置,则表示您已从触发器嵌套。清理部分至关重要。你也祈祷没有其他app / dev做同样的事情,因为每个会话只有一个上下文信息(SQL 2016改进了这一点)。

答案 1 :(得分: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