[英]Merge statement inserting instead of updating in SQL Server
我正在使用SQL Server 2008,並且試圖從暫存(源)表中加載新的(目標)表。 目標表為空。
我認為由於我的目標表為空,因此MERGE語句跳過WHEN MATCHED部分,即INNER JOIN的結果為NULL,因此沒有任何更新,它只是繼續進行到WHEN NOT MATCHED BY TARGET部分(LEFT OUTER JOIN),然后全部插入登台表中的記錄。
我的目標表看起來與我的登台表(行1和行4)完全相似。 目標表中應該只有3行(第4行有3個插入和1個更新)。 因此,我不確定發生了什么。
FileID client_id account_name account_currency creation_date last_modified 210 12345 Cars USD 2013-11-21 2013-11-27 211 23498 Truck USD 2013-09-22 2013-11-27 212 97652 Cars - 1 USD 2013-09-17 2013-11-27 210 12345 Cars JPY 2013-11-21 2013-11-29
QUERY
MERGE [AccountSettings] AS tgt -- RIGHT TABLE
USING
(
SELECT * FROM [AccountSettings_Staging]
) AS src -- LEFT TABLE
ON src.client_id = tgt.client_id
AND src.account_name = tgt.account_name
WHEN MATCHED -- INNER JOIN
THEN UPDATE
SET
tgt.[FileID] = src.[FileID]
,tgt.[account_currency] = src.[account_currency]
,tgt.[creation_date] = src.[creation_date]
,tgt.[last_modified] = src.[last_modified]
WHEN NOT MATCHED BY TARGET -- left outer join: A row from the source that has no corresponding row in the target
THEN INSERT
(
[FileID],
[client_id],
[account_name],
[account_currency],
[creation_date],
[last_modified]
)
VALUES
(
src.[FileID],
src.[client_id],
src.[account_name],
src.[account_currency],
src.[creation_date],
src.[last_modified]
);
由於目標表是空的,因此在我看來,使用MERGE
就像雇用水管工為您倒一杯水。 而且MERGE
對於表的每一行僅獨立地運行一個分支-它看不到鍵是重復的,因此先執行插入操作然后進行更新-這表明您認為SQL總是對行進行操作,實際上,大多數操作是一次對整個集合執行的。
為什么不只插入最近的行:
;WITH cte AS
(
SELECT FileID, ... other columns ...,
rn = ROW_NUMBER() OVER (PARTITION BY FileID ORDER BY last_modified DESC)
FROM dbo.AccountSettings_Staging
)
INSERT dbo.AccountSettings(FileID, ... other columns ...)
SELECT FileID, ... other columns ...
FROM cte WHERE rn = 1;
如果您在最新的last_modified
上可能具有平局,則需要找到另一個平局決勝者(從示例數據中不明顯)。
對於將來的版本,我會說先運行UPDATE
:
UPDATE a SET client_id = s.client_id /* , other columns that can change */
FROM dbo.AccountSettings AS a
INNER JOIN dbo.AccountSettings_Staging AS s
ON a.FileID = s.FileID;
(當然,如果源包含具有相同FileID
多行,這將選擇任意行-您可能也想在此處使用CTE來使選擇可預測。)
然后將此子句添加到上面的INSERT
CTE中:
FROM dbo.AccountSettings_Staging AS s
WHERE NOT EXISTS (SELECT 1 FROM dbo.AccountSettings
WHERE FileID = s.FileID);
以適當的隔離級別將所有內容包裝在事務中,並且您仍在避免大量復雜的MERGE
語法,潛在的錯誤等。
我認為由於目標表為空,因此MERGE語句會跳過WHEN MATCHED部分
是的,這是正確的,但這是設計MERGE
不是“漸進式”合並。 它不會逐行查看是否現在應該更新作為MERGE
一部分插入的記錄。 它根據是否在目標中找到匹配項,以“批次”方式處理源。
在嘗試MERGE
之前,您需要在源頭處理“重復”記錄。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.