子查询返回的值超过1 - 我的触发器无法处理多行更新

时间:2014-07-02 10:58:22

标签: sql sql-server sql-server-2008 triggers

我在名为 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

在触发器中处理多行更新的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

所以,我认为我已经在整个过程中跟踪了你的逻辑,并将其设置为基础。我已经尝试对这两个部分进行了适当的评论,但是有很多事情要发生,所以请随时让我详细说明某些部分。

基础似乎只有dbo.IC_CanSyncProduct(i.ItemID) = 1受影响的记录才有3个分支:

  1. IC_ProductCreateQueue

    中不存在项目
      

    - >插入IC_ProductCreateQueueIC_ProductUpdateQueue

  2. 关键字段已更新,该项目同时存在IC_ProductCreateQueueIC_ProductUpdateQueue

      

    - >更新IC_ProductUpdateQueue

  3. 关键字段已更新,该项目同时存在IC_ProductCreateQueue但不存在IC_ProductUpdateQueue

      

    - >插入IC_ProductUpdateQueue

  4. 方案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