我在名为 StockItem 的表上有一个触发器,它触发MSSQL中的表行更新事件。
如果只更新了一行(即一个产品),则触发器似乎有效。
但是,当更新了多行时,我收到以下错误:
Msg 512,Level 16,State 1,Procedure IC_ProductUpdate,Line 7
子查询返回的值超过1。这是不允许的 子查询跟随=,!=,<,< =,>,> =或当子查询用作 一种表达。声明已经终止。
这是我的触发器:
ALTER TRIGGER [dbo].[IC_ProductUpdate] ON [dbo].[StockItem]
AFTER UPDATE
AS
BEGIN
-- Get Product Id
DECLARE @StockItemID INT = (SELECT ItemID FROM INSERTED);
-- Proceed If This Product Is Syncable
IF (dbo.IC_CanSyncProduct(@StockItemID) = 1)
BEGIN
-- Check If Product Was Synced
IF ((SELECT COUNT(*) FROM IC_ProductCreateQueue WHERE StockItemID = @StockItemID) > 0)
BEGIN
-- Check If Any Important Columns Was Updated
IF (UPDATE(Weight) OR UPDATE(SpareNumber1))
BEGIN
-- Check If There Is A [ProductUpdate] Queue Entry Already Exist For This Product
IF ((SELECT COUNT(*) FROM IC_ProductUpdateQueue WHERE StockItemID = @StockItemID) > 0)
BEGIN
-- Reset [ProductUpdate] Queue Entry
UPDATE IC_ProductUpdateQueue SET Synced = 0
WHERE StockItemID = @StockItemID
END
ELSE
BEGIN
-- Insert [ProductUpdate] Queue Entry
INSERT INTO IC_ProductUpdateQueue (StockItemID, Synced) VALUES
(@StockItemID, 0)
END
END
END
ELSE
BEGIN
-- Insert [ProductCreate] Queue Entry
INSERT INTO IC_ProductCreateQueue (StockItemID, Synced) VALUES
(@StockItemID, 0);
-- Insert [ProductUpdate] Queue Entry
INSERT INTO IC_ProductUpdateQueue (StockItemID, Synced) VALUES
(@StockItemID, 0);
END
END
END
在触发器中处理多行更新的最佳方法是什么?
答案 0 :(得分:1)
所以,我认为我已经在整个过程中跟踪了你的逻辑,并将其设置为基础。我已经尝试对这两个部分进行了适当的评论,但是有很多事情要发生,所以请随时让我详细说明某些部分。
基础似乎只有dbo.IC_CanSyncProduct(i.ItemID) = 1
受影响的记录才有3个分支:
IC_ProductCreateQueue
- >插入
IC_ProductCreateQueue
和IC_ProductUpdateQueue
关键字段已更新,该项目同时存在IC_ProductCreateQueue
和IC_ProductUpdateQueue
- >更新
IC_ProductUpdateQueue
关键字段已更新,该项目同时存在IC_ProductCreateQueue
但不存在IC_ProductUpdateQueue
- >插入
IC_ProductUpdateQueue
方案2和方案3由下面的MERGE
管理,方案1由insert语句处理。
ALTER TRIGGER [dbo].[IC_ProductUpdate] ON [dbo].[StockItem]
AFTER UPDATE
AS
BEGIN
-- MERGE ITEMS INTO UPDATE QUEUE WHERE KEY FIELDS WERE UPDATED
-- AND PRODUCT CAN BE SYNCED AND THE ITEM EXISTS IN THE CREATE QUEUE
WITH MergeData AS
( SELECT i.ItemID
FROM inserted AS i
INNER JOIN deleted AS d
ON d.ItemID = i.ItemID
WHERE dbo.IC_CanSyncProduct(i.ItemID) = 1
AND (i.SpareNumber1 != d.SpareNumber1 OR i.Weight != d.Weight)
AND EXISTS
( SELECT 1
FROM IC_ProductCreateQueue AS pcq
WHERE pcq.StockItemID = i.ItemID
)
)
MERGE IC_ProductUpdateQueue AS puq
USING MergeData AS i
ON i.ItemID = puq.StockItemID
WHEN MATCHED THEN
UPDATE SET Synced = 1
WHEN NOT MATCHED THEN
INSERT (StockItemID, Synced)
VALUES (i.ItemID, 0);
-- INSERT INTO BOTH THE UPDATE AND CREATE QUEUES WHERE THE ITEM
-- DOES NOT ALREADY EXIST IN THE CREATE QUEUE AND THE PRODUCT
-- CAN BE SYNCED
INSERT IC_ProductCreateQueue (StockItemID, Synced)
OUTPUT inserted.StockItemID, inserted.Synced
INTO IC_ProductUpdateQueue (StockItemID, Synced)
SELECT i.ItemID, 0
FROM inserted AS i
WHERE dbo.IC_CanSyncProduct(i.ItemID) = 1
AND NOT EXISTS
( SELECT 1
FROM IC_ProductCreateQueue AS pcq
WHERE pcq.StockItemID = i.ItemID
);
END