更新触发器后 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
但是,当我尝试将 MPRMain
的 Status
设置为 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 行后不起作用