SQL Server - 在SP执行期间中和触发器

时间:2015-05-05 06:31:07

标签: sql-server stored-procedures triggers

我有两个表,订单和应用程序。

App是"帮助"根据订单填充的表格,然后将通过网络服务的信息传递给智能手机。

为了填充App,我们创建了一个参数化的存储过程,该过程在特定时间运行,将数据从Orders流畅地传递给App。

但是这些存储过程并未捕获对Orders的某些更新,因此我们被要求在Orders上创建一个触发器,在这些特定实例中执行此SP。这也很好。

当更新从智能手机到达桌面App时,问题就开始了。相同的参数化SP运行"反向"更新Orders中的字段,这很有效 - 除了这样做可以触发我们所谓的选择性触发器,导致冗余更新。为了证明:

订单中的新行> SP>行用App>编写应用程序更新的应用程序> SP>订单中的相应行已更新>触发器捕获此更新,再次触发SP。

在这个链条中,只有最后一步是个问题。

我尝试在SP中使用DISABLE TRIGGER和ENABLE TRIGGER来避免这个问题,但这是有风险的业务,当然不可能是最好的方法。

我现在正在使用的解决方案是在应用程序更新Orders期间使用 更新的字段,但不会在任何其他时间更新。例如:

UPDATE Orders
SET Orders.StartTime = getdate(),
    Orders.EndTime = CASE ... END,
    Orders.Unique_Field = X
WHERE Orders.ID = @APPID

在Orders的标准更新中,字段Unique_Field不包含在任何INSERT或UPDATE语句中。但是,在App的某些更新中,此字段可能仍为NULL。

我的问题是:告诉我的触发器忽略从我的SP到达的任何更新的正确和安全的方法是什么?

目前,我的触发器如下:

AFTER UPDATE, INSERT
NOT FOR REPLICATION
AS
BEGIN
    DECLARE @BUILDORDERCHECK AS DATETIME
    DECLARE @ORDERDATECHECK AS DATETIME
    DECLARE @ORDERNO AS INT
    DECLARE @CHECKER AS TINYINT
    SELECT @BUILDORDERCHECK = I.UpdateRecordDate,
    @ORDERDATECHECK = I.OrderDate,
    @ORDERNO = I.OrderNo,
    @CHECKER = CASE WHEN NOT EXISTS (SELECT Unique_Field FROM Inserted) THEN 1 ELSE 0 END
    FROM Inserted I

    IF @BUILDORDERCHECK IS NOT NULL 
    AND @ORDERDATECHECK >= dateadd(day,-2,getdate())
    AND @CHECKER = 1
    -- Does not fire from BuildOrder
    -- Does not fire on tasks older than 2 days
        BEGIN
            EXECUTE [dbo].[Asp_Apper;1] 0, -- CallCode, DO NOT CHANGE
                                        1, -- Auto, 
                                        1, -- AOK, 
                                        0, -- CancelMsg, 
                                        0, -- TrailerNo
                                        1  -- RejectMsg
        END
END

@BUILDORDERCHECK和@ORDERDATECHECK正常工作并按预期运行,但我需要找到正确的方法来告诉我的触发器检查并查看更新语句中是否包含Unique_Field而不会被NULLS纠缠。正如我所说的,可以通过SP将Unique_Field更新为NULL值,因此只检查NULL并不起作用。

提前感谢你们所有的想法...

编辑:已经指出这个触发器似乎忽略了更新多行的情况,这是准确的。通常,我们不会像这样构建触发器;但在这种情况下,对订单的更新只是逐行的,而且从不在组中。这种情况的唯一时间是SP运行时,我们无论如何都要忽略它。

1 个答案:

答案 0 :(得分:0)

我会使用CONTEXT_INFOSET CONTEXT_INFO,如下所示:

在触发器中,如果设置了特定的上下文值,则在顶部添加一个检查结果:

IF ISNULL(CONTEXT_INFO(),0x0) = 0x49204C696B6520426967204275747473
   RETURN

然后在您想要执行被忽略的操作的存储过程的(部分)中,只需设置相同的值:

SET CONTEXT_INFO 0x49204C696B6520426967204275747473;
--Code that shouldn't cause the trigger to fire
SET CONTEXT_INFO 0x0

保持包含的内容(与禁用具有全局效果的触发器不同)

此外,我知道您已经在评论中说过,此触发器只需工作进行单行更新,但对于任何触发器而言,对我来说代码审查会自动失败没有正确处理inserted中存在的多个行(或者至少,检查行数,并且如果单行更新的要求没有&且给出明确的错误消息已经完成了