2013-10-16 26 views
3

我需要MERGE一組記錄到表中。源中的UpdateType列確定目標中是否應該有DELETE行不在源中。如何才能「全部刪除」,但只有當某列具有特定值時纔可以?

所以UpdateType將等於DR ... d =三角洲,R =刷新

如果D,不DELETE從目標
如果R不匹配,從目標DO DELETE不匹配。

我有一個WHILE遍歷單個表,以更好地模仿過程如何工作。

我可以在MERGE中完成這項工作嗎?或者我有什麼其他選擇?

SQL小提琴:http://www.sqlfiddle.com/#!3/9cdfe/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 

[email protected] Expected Result: 
-- 1 'R' 1 'Small Wheel' 
-- 1 'R' 4 'Trunk' 
+0

對不起,我不完全理解你的輸出。那裏爲什麼沒有'ItemNumber = 2'? – Lamak

+0

因爲當它迭代到'RN = 4'時,'UpdateType ='R'將會「刪除@ tab中所有不匹配的內容」。由於'RN = 4',沒有'ItemNumber = 2'的記錄,這將被刪除,只有'ItemNumber = 1'將被更新。 'RN = 5'將更新'ItemNumber = 1'並插入'ItemNumber = 4'。這些幫助有用? – MisterIsaak

回答

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 
+0

問題是,如果'UpdateType ='R'',我需要刪除整個'Store'的所有內容,這就是爲什麼我不認爲我可以使用'MERGE',但我希望我錯了。數據變平,所以'UpdateType'對每個迭代/'RN'都是一樣的。並感謝您清理'CASE'聲明。 – MisterIsaak

+0

我有一個解決方案,但是,當我嘗試發佈編輯或新答案時,我總是收到錯誤。關鍵是:對於提交給MERGE過程的每條記錄(使用遊標),如果是'UpdateType ='D''和'MERGE' *而沒有*'DELETE',則需要測試'MERGE'如果不是,則使用* DELETE。問題解決後,我會糾正我的答案。 –

+0

最後克服了stackoverflow錯誤。現在看看我的答案。 –

相關問題