我正在使用SQL Server 2008,我正在尝试从登台(源)表加载新的(目标)表。目标表是空的。
我认为因为我的目标表是空的,MERGE语句跳过WHEN MATCHED部分,即INNER JOIN的结果为NULL,因此没有任何更新,它只是继续到目标不匹配的部分(LEFT OUTER JOIN) a在登台表中插入所有记录。
我的目标表看起来与我的临时表(行#1和#4)完全相似。目标表中应该只有3行(3行插入和第4行更新)。所以,我不确定最新情况。
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]
);
答案 0 :(得分:3)
由于目标表是空的,使用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
语法,潜在的错误等。
答案 1 :(得分:2)
我认为由于我的目标表是空的,MERGE语句会跳过WHEN MATCHED部分
嗯,这是正确的,但它是设计的 - MERGE
不是“渐进式”合并。它不会逐行查看是否应该更新作为MERGE
的一部分插入的记录。它根据是否在目的地中找到匹配来“批量处理”源。
在尝试MERGE
之前,您需要在源处理“重复”记录。