3

我需要将MERGE一组记录放入一个表中。源中的UpdateType列确定我是否应该DELETE在目标中的行不在源中。

所以UpdateType将等于DR... D=Delta, R=Refresh

如果D,不DELETE与目标不匹配
如果RDELETE不与目标不匹配。

我有一个WHILE迭代单个表的方法,以更好地模拟该过程的工作方式。

我可以在 MERGE 中完成此操作吗?或者我还有什么其他选择?

SQL 小提琴: http ://www.sqlfiddle.com/#!3/9cfe/16

这是我的例子,唯一的问题是......我不能在WHEN NOT MATCHED BY SOURCE子句中使用源值。

DECLARE @BaseTable TABLE
(   RN int  
    ,Store int
    ,UpdateType char(1)
    ,ItemNumber int
    ,Name varchar(50)
)

INSERT INTO @BaseTable
SELECT *
FROM
(
    SELECT 1 RN, 1 Store, 'D' UpdateType, 1 ItemNumber, 'Wheel' Name
    UNION ALL
    SELECT 2, 1, 'D', 1, 'Big Wheel'
    UNION ALL
    SELECT 3, 1, 'D', 2, 'Light'
    UNION ALL
    SELECT 4, 1, 'R', 1, 'Wide Wheel'
    UNION ALL
    SELECT 5, 1, 'D', 1, 'Small Wheel'
    UNION ALL
    SELECT 5, 1, 'D', 4, 'Trunk'
)B

SELECT bt.* FROM @BaseTable bt

DECLARE @Tab TABLE
(   Store int
    ,UpdateType char(1)
    ,ItemNumber int
    ,Name varchar(50)
)

DECLARE @count int = 1
--Loop over each row to mimic how the merge will be called.
WHILE @count <= 5
BEGIN  
    MERGE INTO @Tab T
    USING
    (
        SELECT bt.RN,
                bt.Store,
                bt.UpdateType,
                bt.ItemNumber,
                bt.Name,
                tab.Store IsRefresh
        FROM @BaseTable bt
        LEFT JOIN
        (   --If ANY previous ITERATION was a 'R' then, all subsequent UpdateType MUST = 'R'
            --I'm hoping there is a better way to accomplish this.
            SELECT Store
            FROM @Tab
            WHERE UpdateType = 'R'
            GROUP BY Store
            HAVING COUNT(Store) > 1
        )tab
            ON bt.Store = tab.Store
        WHERE bt.RN = @count
    )S
        ON S.Store = T.Store AND S.ItemNumber = T.ItemNumber
    WHEN MATCHED THEN
        UPDATE
        SET T.UpdateType = CASE WHEN S.IsRefresh IS NOT NULL THEN 'R' ELSE S.UpdateType END,
        T.Name = S.Name
    WHEN NOT MATCHED BY TARGET THEN
        INSERT(Store,UpdateType,ItemNumber,Name) VALUES(S.Store,S.UpdateType,S.ItemNumber,S.Name)
    --WHEN NOT MATCHED BY SOURCE AND S.UpdateType = 'R' THEN
    --  DELETE
        ;
    SET @count = @count + 1
END

SELECT * FROM @Tab

--@Tab Expected Result:
-- 1 'R' 1 'Small Wheel'
-- 1 'R' 4 'Trunk'
4

1 回答 1

1

以下代码似乎可以执行您想要的操作:

CREATE TABLE #BaseTable
(   RN int  
    ,Store int
    ,UpdateType char(1)
    ,ItemNumber int
    ,Name varchar(50)
)

INSERT INTO #BaseTable
SELECT *
FROM
(
    SELECT 1 RN, 1 Store, 'D' UpdateType, 1 ItemNumber, 'Wheel' Name
    UNION ALL
    SELECT 2, 1, 'D', 1, 'Big Wheel'
    UNION ALL
    SELECT 3, 1, 'D', 2, 'Light'
    UNION ALL
    SELECT 4, 1, 'R', 1, 'Wide Wheel'
    UNION ALL
    SELECT 5, 1, 'D', 1, 'Small Wheel'
    UNION ALL
    SELECT 5, 1, 'D', 4, 'Trunk'
)B

CREATE TABLE #Tab
(   Store int
    ,UpdateType char(1)
    ,ItemNumber int
    ,Name varchar(50)
)
SELECT bt.* FROM #BaseTable bt  -- Output for debugging - delete in production. 

DECLARE @count int = 1
DECLARE @Input TABLE (Store int, UpdateType char(1), ItemNumber int, Name varchar(50))
--Loop over each row to mimick how the merge will be called.
WHILE @count <= 5
BEGIN
    DELETE FROM @Input
    INSERT INTO @Input SELECT Store, UpdateType, ItemNumber, Name  FROM #BaseTable WHERE RN = @Count

    SELECT * FROM @Input    -- Output for debugging - delete in production.

    -- Procedure Body
    DECLARE @Store int, @UpdateType char(1), @ItemNumber int, @Name varchar(50)
    DECLARE csrInput CURSOR FOR SELECT Store, UpdateType, ItemNumber, Name  FROM @Input
    OPEN csrInput
    WHILE 1=1
        BEGIN
            FETCH NEXT FROM csrInput INTO @Store, @UpdateType, @ItemNumber, @Name 
            IF @@FETCH_STATUS<>0 BREAK
            IF @UpdateType = 'D'
                MERGE INTO #Tab Dest
                USING (SELECT * FROM @Input WHERE Store = @Store AND ItemNumber = @ItemNumber) Src
                ON Dest.Store = Src.Store AND Dest.ItemNumber = Src.ItemNumber
                WHEN MATCHED THEN UPDATE SET Dest.UpdateType = Src.UpdateType, Dest.Name = Src.Name
                WHEN NOT MATCHED BY TARGET THEN INSERT (Store, UpdateType, ItemNumber, Name) VALUES (Src.Store, Src.UpdateType, Src.ItemNumber, Src.Name);
            ELSE    -- Assuming that @UpdateType can only be 'D' or 'R'...
                MERGE INTO #Tab Dest
                USING (SELECT * FROM @Input WHERE Store = @Store AND ItemNumber = @ItemNumber) Src
                ON Dest.Store = Src.Store AND Dest.ItemNumber = Src.ItemNumber
                WHEN MATCHED THEN UPDATE SET Dest.UpdateType = Src.UpdateType, Dest.Name = Src.Name
                WHEN NOT MATCHED BY TARGET THEN INSERT (Store, UpdateType, ItemNumber, Name) VALUES (Src.Store, Src.UpdateType, Src.ItemNumber, Src.Name)
                WHEN NOT MATCHED BY SOURCE THEN DELETE;

                SELECT * FROM #Tab  -- Output for debugging - delete in production. 

        END
    CLOSE csrInput
    DEALLOCATE csrInput
    -- End Procedure Body.

    SET @count += 1
END

最终输出:

Store UpdateType ItemNumber Name
1     D          1          Small Wheel
1     D          4          Trunk
于 2013-10-16T21:58:47.590 回答