【发布时间】:2019-03-06 09:43:36
【问题描述】:
我有一个合并语句,我想在其中更新我的表行,以防任何列具有不同的值。但似乎即使源表中的大多数行都保持不变,MERGE 语句执行UPDATE 至少计算它所做的UPDATE。
DECLARE @SummaryOfChanges TABLE(Change VARCHAR(50));
MERGE MyTarget AS TARGET
USING MySource AS SOURCE
ON (SOURCE.customeridHash = TARGET.Id)
WHEN MATCHED AND (TARGET.IsCompany <> SOURCE.company
OR TARGET.Gender <> SOURCE.gender
OR TARGET.BirthDate <> CONVERT(DATE, SOURCE.dateofbirth)
OR TARGET.ZipCode <> SOURCE.ZipCode
OR TARGET.City <> SOURCE.City
OR TARGET.WantsEmail <> (CASE WHEN SOURCE.noemail = 0 THEN 1 ELSE 0 END)
OR TARGET.WantsSMS <> (CASE WHEN SOURCE.nosms = 0 THEN 1 ELSE 0 END)
OR TARGET.WantsDM <> (CASE WHEN SOURCE.nodirectmarketing = 0 THEN 1 ELSE 0 END)
OR TARGET.WantsTM <> (CASE WHEN SOURCE.notelemarketing = 0 THEN 1 ELSE 0 END)
OR TARGET.HasEmail <> SOURCE.HasEmail
OR TARGET.HasMobilePhoneNumber <> SOURCE.HasMobilePhoneNumber
OR TARGET.HasPhoneNumber = SOURCE.HasPhoneNumber
OR TARGET.Created <> SOURCE.Created
OR TARGET.Updated <> SOURCE.changed)
THEN
UPDATE SET TARGET.IsCompany = SOURCE.company,
TARGET.Gender = SOURCE.gender,
TARGET.BirthDate = CONVERT(DATE, SOURCE.dateofbirth),
TARGET.ZipCode = SOURCE.ZipCode,
TARGET.City = SOURCE.City,
TARGET.WantsEmail = (CASE WHEN SOURCE.noemail = 0 THEN 1 ELSE 0 END),
TARGET.WantsSMS = (CASE WHEN SOURCE.nosms = 0 THEN 1 ELSE 0 END),
TARGET.WantsDM = (CASE WHEN SOURCE.nodirectmarketing = 0 THEN 1 ELSE 0 END),
TARGET.WantsTM = (CASE WHEN SOURCE.notelemarketing = 0 THEN 1 ELSE 0 END),
TARGET.HasEmail = SOURCE.HasEmail,
TARGET.HasMobilePhoneNumber = SOURCE.HasMobilePhoneNumber,
TARGET.HasPhoneNumber = SOURCE.HasPhoneNumber,
TARGET.Created = SOURCE.Created,
TARGET.Updated = SOURCE.changed
WHEN NOT MATCHED BY TARGET THEN
INSERT (
Id,
IsCompany,
Gender,
BirthDate,
ZipCode,
City,
WantsEmail,
WantsSMS,
WantsDM,
WantsTM,
HasEmail,
HasMobilePhoneNumber,
HasPhoneNumber,
Created,
Updated
)
VALUES (
SOURCE.customeridHash,
SOURCE.company,
SOURCE.gender,
CONVERT(DATE, SOURCE.dateofbirth),
SOURCE.ZipCode,
SOURCE.City,
(CASE WHEN SOURCE.noemail = 0 THEN 1 ELSE 0 END),
(CASE WHEN SOURCE.nosms = 0 THEN 1 ELSE 0 END),
(CASE WHEN SOURCE.nodirectmarketing = 0 THEN 1 ELSE 0 END),
(CASE WHEN SOURCE.notelemarketing = 0 THEN 1 ELSE 0 END),
SOURCE.HasEmail,
SOURCE.HasMobilePhoneNumber,
SOURCE.HasPhoneNumber,
SOURCE.Created,
SOURCE.changed
)
WHEN NOT MATCHED BY SOURCE THEN DELETE
OUTPUT $action INTO @SummaryOfChanges;
SELECT Change, COUNT(*) CountPerChange
FROM @SummaryOfChanges
GROUP BY Change;
我在更新结束时做了一些记账(最后的SELECT),似乎几乎所有不是新的行都被更新了。这是一种常见的行为,还是在我的<> 与WHEN MATCHED AND... 的比较中确实有更新的值?
更新:根据其中一位 cmet 的建议,我编写了以下测试来检查我的条件是否触发更新:
-- TEST MERGE
select count(*)
from MyTarget TARGET join MySource SOURCE on TARGET.Id=SOURCE.customeridHash
where TARGET.IsCompany <> SOURCE.company
OR TARGET.Gender <> SOURCE.gender
OR TARGET.BirthDate <> CONVERT(DATE, SOURCE.dateofbirth)
OR TARGET.ZipCode <> SOURCE.ZipCode
OR TARGET.City <> SOURCE.City
OR TARGET.WantsEmail <> (CASE WHEN SOURCE.noemail = 0 THEN 1 ELSE 0 END)
OR TARGET.WantsSMS <> (CASE WHEN SOURCE.nosms = 0 THEN 1 ELSE 0 END)
OR TARGET.WantsDM <> (CASE WHEN SOURCE.nodirectmarketing = 0 THEN 1 ELSE 0 END)
OR TARGET.WantsTM <> (CASE WHEN SOURCE.notelemarketing = 0 THEN 1 ELSE 0 END)
OR TARGET.HasEmail <> SOURCE.HasEmail
OR TARGET.HasMobilePhoneNumber <> SOURCE.HasMobilePhoneNumber
OR TARGET.HasPhoneNumber = SOURCE.HasPhoneNumber
OR TARGET.Created <> SOURCE.Created
OR TARGET.Updated <> SOURCE.changed;
我意识到这个查询返回相同数量的更新。所以它在某种程度上更多的是关于MERGE 语句的条件。但我想知道它们是如何触发更新的。
【问题讨论】:
-
以
select运行此命令以使用using->inner join、when matched and测试您的条件 ->where。 -
这真的很难说,因为我们没有任何样本数据和输出......我注意到的一件事是你有像
OR TARGET.WantsEmail <> (CASE WHEN SOURCE.noemail = 0 THEN 1 ELSE 0 END)这样的条件。在这种情况下,如果source.noemail为 null,您将得到 0 作为 case 表达式的结果——您可能没有注意这一点。 -
另外,必读:Aaron Bertrand's Use Caution with SQL Server's MERGE Statement
-
@ZoharPeled 我做了你建议的
SELECT测试,我意识到我在那里得到了相同数量的更新。所以可能更多的是关于条件和合并。 -
@ZoharPeled 关于
OR TARGET.WantsEmail <> (CASE WHEN SOURCE.noemail = 0 THEN 1 ELSE 0 END)条件,您是否建议每次都会触发更新?
标签: sql-server tsql merge