SQL Server Merge: update only changed data, tracking changes?的后续问题
我们一直在努力让有效的MERGE语句工作,现在正在考虑只使用更新,我们有一个非常简单的问题:从源更新目标,其中值不同并记录更改,两个表的布局相同。
因此,我们面临的两个问题是:能否将这一非常简单的更新合并到一条语句中?
UPDATE tbladsgroups
SET tbladsgroups.Description = s.Description,
tbladsgroups.action='Updated'
FROM tbladsgroups t
INNER JOIN tbladsgroups_staging s
ON t.SID = s.SID
Where s.Description <> t.Description
UPDATE tbladsgroups
SET tbladsgroups.DisplayName = s.DisplayName,
tbladsgroups.action='Updated'
FROM tbladsgroups t
INNER JOIN tbladsgroups_staging s
ON t.SID = s.SID
Where s.DisplayName <> t.DisplayName
...每一栏。
第二项质询。
我们是否可以将已更新的记录记录到单独的表/变量中?
合并将是完美的,但是我们无法看到更新了哪条记录,因为从输出返回的数据显示了所有行,因为目标总是更新的。
编辑完全合并:
M
ERGE tblADSGroups AS TARGET
USING tblADSGroups_STAGING AS SOURCE
ON (TARGET.[SID] = SOURCE.[SID])
WHEN MATCHED
THEN UPDATE SET
TARGET.[Description]=CASE
WHEN source.[Description] != target.[Description] THEN(source.[Description]
)
ELSE target.[Description] END,
TARGET.[displayname] = CASE
WHEN source.[displayname] != target.[displayname] THEN source.[displayname]
ELSE target.[displayname] END
...other columns cut for brevity
WHEN NOT MATCHED BY TARGET
THEN
INSERT (
[SID],[SamAccountName],[DisplayName],[Description],[DistinguishedName],[GroupCategory],[GroupScope],[Created],[Members],[MemberOf],[SYNCtimestamp],[Action]
)
VALUES (
source.[SID],[SamAccountName],[DisplayName],[Description],[DistinguishedName],[GroupCategory],[GroupScope],[Created],[Members],[MemberOf],[SYNCtimestamp],[Action]
)
WHEN NOT MATCHED BY SOURCE
THEN
UPDATE SET ACTION='Deleted'
3条答案
按热度按时间shstlldc1#
可以将单个
UPDATE
与OUTPUT
子句一起使用,并在JOIN子句中使用INTERSECT
或EXCEPT
子查询来检查是否有任何列已更改。例如
如果您还想使用
INSERT
,则可以使用MERGE
执行类似的操作8ehkhllq2#
在处理数据仓库维度中的值时,我们也有类似的需求。合并可以很好地工作,但对于大型表可能效率较低。您的方法可以工作,但效率似乎相当低,因为您将对每个列都有单独的更新。缩短内容的一种方法是比较一条语句中的多个列(这显然会使事情变得更加复杂)。您似乎也没有考虑空值。
我们最终使用的基本上是本页面中描述的技术:https://sqlsunday.com/2016/07/14/comparing-nullable-columns/
使用
INTERSECT
,您可以轻松(快速)比较我们的临时表和维度表之间的差异,而不必为每个单独的列显式编写比较。为了回答您的第二个问题,上面的技术不能让您捕捉到哪一列发生了更改。但是,您可以比较旧行和新行(我们通过设置“ValidTo”日期来“关闭”该行的早期版本,然后添加“ValidFrom”日期等于今天日期的新行。
我们的代码最终如下所示:
INSERT
Stage表中在新表中没有匹配键值的所有行(新行)INTERSECT
比较阶段和维度,并将所有匹配项存储在表变量中INSERT
新行col17t5w3#
我认为你可能过多地考虑了复杂性,但是的。您的底层更新是基于每个查询中匹配的ID在ADS组和临时表之间进行比较。由于您已经在检查ID上的联接并比较不同的描述或显示名称,因此只需更新这两个字段。为什么?
因此,您想要的最终值是将描述和显示从Stage拉回到ADS Groups表中。
在上面的示例中,我有三个示例,如果基于匹配的ID提供条目,则需要更改。如果一列中的值相同,但另一列中的值不同,并且您更新了这两列,则最终的结果是更新了一列错误的列。第一个最终将保持不变。如果两者都不同,无论如何都会更新。
现在,所有这些分辨率都在说,你有冗余的数据,这就是查找表的全部意义。暂存似乎始终具有正确的显示名称和描述。您的tblAdsGroups可能应该删除这两列,并始终从试运行开始时获取它们...就像..。
然后,你总是有正确的描述和显示名称,而不必在它们之间保持同步更新。