更新触发器后 SQL Server 不起作用

Posted

技术标签:

【中文标题】更新触发器后 SQL Server 不起作用【英文标题】:SQL Server After Update Trigger Not Working 【发布时间】:2013-06-17 10:58:10 【问题描述】:

我的架构具有以下结构; 在MPRMain 表中,Status 可以是1(Aprove)、2(Cancel)和3(Pending)。我正在尝试做这样的事情,例如当有人将Status(在 MPRMain 中)更新为 2(Cancel) 时。我想将MPRDetail 表的Status 更新为0(0 表示禁用,1 表示启用)。 所以,我试图为它创建一个触发器,看起来像这样;

Alter Trigger Inventory.MprMainUpdate
    ON Inventory.MPRMain
    AFTER UPDATE
AS
BEGIN 

    declare @status as int;
    set @status = (SELECT Status FROM inserted);
    if(@status=2)
    BEGIN
        UPDATE Inventory.MPRDetail
        SET Status = 0   -- update the status to canceled
        WHERE MPRId = (select MPRId from inserted);
    END

END

但是,当我尝试将 MPRMainStatus 设置为 2(取消)1(批准) 时,我没有看到任何MPRDetail 表中的更改。这应该将MPRDetail 状态更新为 0(0 表示禁用)。

【问题讨论】:

您的第一个问题是您错误地假设触发器每行调用一次 - 事实并非如此。它被称为每个语句一次,并且您的Inserted 表可以(并且!)包含多行 - 所以你用set @status = (SELECT Status FROM inserted); 选择哪一个 - 这是未定义。您需要重写触发器以考虑到Inserted(和Deleted包含多行!您需要使用基于集合的方法来处理这些问题 @marc_s,您提供的任何示例将不胜感激。我以前没用过触发器。 【参考方案1】:

由于Inserted 可以包含多行,您需要使用基于集合的方法编写触发器:

ALTER TRIGGER Inventory.MprMainUpdate
    ON Inventory.MPRMain AFTER UPDATE
AS
BEGIN 
  UPDATE Inventory.MPRDetail
  SET Status = 0
  FROM Inserted i
  WHERE i.Status = 2 AND Inventory.MPRDetail.MPRId = i.MPRId;
END

所以基本上你需要根据MPRId 列将你的实际数据表与Inserted 伪表连接起来,并将基表中的所有行更新为Status = 0 其中Inserted.Status = 2

好的 - 我开始了:假设您的 UPDATE 语句更新了四行,那么 Inserted 在您的触发器中可能如下所示:

MPRId  MprNo  Date  DepartmentId  Status
  1      42     ..    .......        1
  2      43     ..    .......        2
  7      33     ..    .......        7
  9      41     ..    .......        2

现在,你 JOIN 这组数据对照你的 MPRDetail 表,你只选择 Inserted 中的 Status 为 2 的那些行 - 所以你得到

MPRId  Status  MPRDetail.Status  (other columns of MPRDetail for those values)
  2      2           4           .....................................
  9      2           5           .....................................

所以在这种情况下,MPRDetail 中的这两行都会在触发器内将它们的Status 更新为 0 - 不会触及任何其他行。

这会让事情变得更清楚吗?如果不是:你在哪里卡住了,还有什么“魔法”让你不清楚?

【讨论】:

我应该删除前 3 行,即 if 条件 @DotNetDreamer:是的 - 因为当你使用我的触发器时完全不需要这些行 - 该代码检查相同的条件 抱歉,效果很好。我可以有更多描述性的答案或可以帮助我的链接吗? 现在一切都清楚了。亲爱的,感谢您抽出宝贵的时间:D 这件事在mysql 很容易,而在SQL Server 很难做到。

以上是关于更新触发器后 SQL Server 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008 - CAST 到 nvarchar 不起作用

触发器中的 ORACLE SQL 更新语句在 2 行后不起作用

sql-server 堆栈查询 sql 注入更新查询不起作用

更新存储过程在 SQL Server 中不起作用

SQL Server:合并语句的更新部分不起作用

在 Management Studio 中编辑后 SQL Server 视图不起作用