繁体   English   中英

结合条件多次更新,更好的合并?

[英]Combine multiple updates with conditions, better merge?

SQL 服务器合并的跟进问题:仅更新更改的数据,跟踪更改?

我们一直在努力使有效的合并语句起作用,现在正在考虑仅使用更新,我们有一个非常简单的问题:从值不同的源更新目标并记录更改,两个表的布局相同。

所以,我们有两个问题:是否可以将这个非常简单的更新合并到一个语句中?

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

....对于每一列。

第二个问题。

我们可以将更新的记录记录到单独的表/变量中吗?

合并将是完美的,但是我们无法看到更新了哪条记录,因为从 OUTPUT 返回的数据显示了所有行,因为目标始终在更新。

编辑完整合并:

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'

在处理数据仓库维度中的值时,我们有类似的需求。 合并工作正常,但对于大表可能效率低下。 您的方法可行,但似乎效率很低,因为您会对每一列进行单独更新。 缩短事情的一种方法是比较一个语句中的多个列(这显然会使事情变得更复杂)。 您似乎也没有考虑 NULL 值。

我们最终使用的基本上是此页面上描述的技术: https://sqlsunday.com/2016/07/14/comparing-nullable-columns/

使用INTERSECT可以让您轻松(快速)比较暂存表和维度表之间的差异,而无需为每个单独的列显式编写比较。

要回答你的第二个问题,上面的技术不会让你捕捉到哪一列发生了变化。 但是,您可以比较旧行与新行(我们通过设置“ValidTo”日期来“关闭”该行的早期版本,然后添加“ValidFrom”日期等于今天的新行。

我们的代码最终看起来像下面这样:

  • INSERT阶段表中在新表中没有匹配键值的所有行(新行)
  • 使用INTERSECT比较阶段与维度并将所有匹配项存储在表变量中
  • 使用表变量,“关闭”维度中的所有匹配行
  • 使用表变量, INSERT新行
  • 如果发生满载,我们还可以检查仅存在于维度中但不存在于阶段表中的键。 这表明这些行已在源系统中删除,我们在维度中将它们标记为“IsDeleted”。

您可以使用带有OUTPUT子句的单个UPDATE ,并在连接子句中使用INTERSECTEXCEPT子查询来检查是否有任何列已更改。

例如

UPDATE t
SET Description = s.Description,
    DisplayName = s.DisplayName,
    action = 'Updated'
OUTPUT inserted.ID, inserted.Description, inserted.DisplayName
INTO @tbl (ID, Description, DisplayName)
FROM tbladsgroups t
INNER JOIN tbladsgroups_staging s
  ON t.SID = s.SID
  AND NOT EXISTS (
    SELECT s.Description, s.DisplayName
    INTERSECT
    SELECT t.Description, t.DisplayName
  );

如果你还想INSERT ,你可以用MERGE做类似的事情

MERGE tbladsgroups t
USING tbladsgroups_staging s
  ON t.SID = s.SID
WHEN MATCHED AND NOT EXISTS (    -- do NOT place this condition in the ON
    SELECT s.Description, s.DisplayName
    INTERSECT
    SELECT t.Description, t.DisplayName
  )
  THEN UPDATE SET
    Description = s.Description,
    DisplayName = s.DisplayName,
    action = 'Updated'
WHEN NOT MATCHED
  THEN INSERT (ID, Description, DisplayName)
       VALUES (s.ID, s.Description, s.DisplayName)
OUTPUT inserted.ID, inserted.Description, inserted.DisplayName
INTO @tbl (ID, Description, DisplayName)
;

我认为您可能过度考虑了复杂性,但是是的。 您的基础更新是根据每个查询中的匹配 ID 对广告组和登台表进行比较。 由于您已经在检查 ID 上的连接并比较不同的描述或显示名称,因此只需更新这两个字段。 为什么?

groups description   groups display   staging description  staging display
SomeValue            Show Me          SOME other Value     Show Me
Try This             Attempt          Try This             Working on it
Both Diff            Changes          Both Are Diff        Change Me

因此,您想要的最终价值是将描述和展示从登台拉回广告组表。

在上面的示例中,我有三个示例,如果基于匹配的 ID 显示需要更改的条目。 如果一列中的值相同,而另一列中的值不同,并且您更新了两列,则 .net 效果是更新的一个坏列。 第一个最终将保持不变。 如果两者不同,无论如何都会更新。

UPDATE        tbladsgroups
SET           tbladsgroups.Description = s.Description,
              tbladsgroups.DisplayName = s.DisplayName,
              tbladsgroups.action='Updated'
FROM          tbladsgroups t
INNER JOIN    tbladsgroups_staging s
ON            t.SID = s.SID
Where   s.Description   <> t.Description 
   OR   s.DisplayName   <> t.DisplayName

现在,所有这些解决方案都在说,你有冗余数据,这就是查找表的全部意义所在。 暂存似乎始终具有正确的显示名称和描述。 您的 tblAdsGroups 可能应该删除这两列,并始终将它们从登台开始...

select
      t.*,
      s.Description,
      s.DisplayName
   from
      tblAdsGroups t
         JOIN tblAdsGroups_Staging s
            on t.sid = s.sid 

然后您始终拥有正确的描述和显示名称,而不必在它们之间保持同步更新。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM