Sql-Server

如何在 SQL Server 的多鍵 MERGE 中僅刪除相關記錄?

  • May 8, 2020

假設你有這樣的東西:

源表(變數):

Values (
 LeftId INT NOT NULL,
 RightId INT NOT NULL,
 CustomValue varchar(100) NULL
)

目標表:

Mapping (
 LeftId INT NOT NULL,
 RightId INT NOT NULL,
 CustomValue varchar(100) NULL
)

我想合併ValuesTarget以下規則:

  • 匹配上source.LeftId = target.LeftId AND source.RightId = target.RightId
    • 在目標中匹配時,更新CustomValue
    • 當目標中不匹配時,插入
  • 刪除目標中與源中的a 匹配的任何不匹配值*,*LeftId即僅刪除與LefId我正在合併的 s 相關的記錄。

(最後一條規則很難描述,抱歉!)

例如:

資源:

1, 10, foo
1, 11, foo

目標:

1, 10, bar
1, 12, foo
2, 20, car

合併結果:

結果目標:

1, 10, foo (updated)
1, 11, foo (inserted)
1, 12, foo (deleted)
2, 20, car (unchanged)

所以…

這是我到目前為止所擁有的,它負責updateand insert

MERGE Mapping AS target
USING (SELECT LeftId, RightId, CustomValue FROM @Values) 
 AS source (LeftId, RightId, CustomValue)
 ON target.LeftId = source.LeftId
   AND target.RightId = source.RightId
WHEN NOT MATCHED THEN
 INSERT (LeftId, RightId, CustomValue)
 VALUES (source.LeftId, source.RightId, source.CustomValue)
WHEN MATCHED THEN
 UPDATE SET
   CustomValue = source.CustomValue;

我該如何做delete我的規則的一部分?

這是DELETE我想到的單獨操作:

DELETE m
FROM dbo.Mapping AS m
WHERE EXISTS 
 (SELECT 1 FROM @Values WHERE LeftID = m.LeftID)
AND NOT EXISTS 
 (SELECT 1 FROM @Values WHERE LeftID = m.LeftID AND RightID = m.RightID);

正如我在這裡概述的那樣,對於左反半連接,該NOT EXISTS模式通常會優於該LEFT JOIN / NULL模式(但您應該始終進行測試)。

不確定您的總體目標是清晰度還是性能,因此只有您可以判斷這是否比NOT MATCHED BY source選項更符合您的要求。您必須定性地查看計劃,定量地查看計劃和/或執行時指標,才能確定。

如果您希望您的MERGE命令保護您免受多個獨立語句可能發生的競爭條件的影響,您最好通過將其更改為:

MERGE dbo.Mapping WITH (HOLDLOCK) AS target

(來自Dan Guzman 的博文。)

就個人而言,我會在沒有 的情況下完成所有這些MERGE,因為存在未解決的錯誤以及其他原因。並且Paul White 似乎也推薦單獨的 DML 語句

這就是我添加模式前綴的原因:在創建、影響等時,您應該始終按模式引用對象

引用自:https://dba.stackexchange.com/questions/48055