子查询返回超过 1 个值 - 我的触发器无法处理多个行更新
Posted
技术标签:
【中文标题】子查询返回超过 1 个值 - 我的触发器无法处理多个行更新【英文标题】:Subquery returned more than 1 value - My trigger cannot handle more than one row update 【发布时间】:2014-07-02 10:58:22 【问题描述】:我在名为 StockItem 的表上有一个触发器,它在 MSSQL 中的表行更新事件时触发。
如果只更新一行(即一种产品),触发器似乎可以工作。
但是,当更新不止一行时,我收到以下错误:
消息 512,级别 16,状态 1,过程 IC_ProductUpdate,第 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
在我的触发器中处理多行更新的最佳方式是什么?
【问题讨论】:
【参考方案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
【讨论】:
谢谢 GarethD,你简直太棒了!这个更新的触发器完美无缺。 :) !!!以上是关于子查询返回超过 1 个值 - 我的触发器无法处理多个行更新的主要内容,如果未能解决你的问题,请参考以下文章
子查询返回超过 1 个值。当子查询跟随 = 或子查询用作表达式时,这是不允许的