[英]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.