子查询返回超过 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_ProductCreateQueueIC_ProductUpdateQueue

    关键字段已更新,并且该项目同时存在于 IC_ProductCreateQueueIC_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 个值。当子查询跟随 = 或子查询用作表达式时,这是不允许的

子查询返回超过 1 个值。这是啥意思?

存储过程生成 msg 512 子查询返回超过 1 个值

SQL Server 子查询返回超过 1 个值。子查询遵循 =, !=, <, <= , >, >=

子查询在 sqlc# 中返回超过 1 个值

TSQL:SELECT CASE WHEN THEN 子查询:错误:子查询返回超过 1 个值