【问题标题】:T-SQL Slowly Changing Dimension - Multiple Updates, Single Action Output?T-SQL 渐变维度 - 多次更新,单次操作输出?
【发布时间】:2019-08-16 10:15:09
【问题描述】:

我已经为我正在处理的仓库实施了四个 SCD,它们正在发挥作用。希望我已经正确理解了 SCD 方法,并且假设我已经理解了,我现在有一个问题需要帮助。

问题在于,有些字段无需创建新维度即可更新,因为它们与时间无关。所以在 MERGE 语句中我想有两个语句:

WHEN MATCHED AND tgt.HashBytes_Value <> src.HashBytes_Value
THEN 
   UPDATE Row_Expiry_Details
WHEN MATCHED AND tgt.HashBytes_Value = src.HashBytes_Value
THEN
   UPDATE Columns_That_Are_Not_SCD_Relevant
etc..

我不确定如何在查询中添加第二个 WHEN MATCHED。

这是一个现在运行良好的代码示例,但没有按照我的意愿执行。

-- Created temp tables for example
DROP TABLE IF EXISTS #StagingTable
CREATE TABLE #StagingTable
(
    id INT,   
    name VARCHAR(20),
    team VARCHAR(20),
    preferences VARCHAR(50),
    hashbytes_Value VARBINARY(20)
)

DROP TABLE IF EXISTS #PresTable

CREATE TABLE #PresTable
(
    dim_id INT IDENTITY(1,1) PRIMARY KEY,
    id INT,
    name VARCHAR(20),
    team VARCHAR(20),   
    preferences VARCHAR(50),
    hashbytes_Value VARBINARY(20),
    row_Current_ind BIT DEFAULT(1),
    row_effective_date DATETIME2 DEFAULT(SYSDATETIME()),
    row_expiry_date DATETIME2 DEFAULT(SYSDATETIME())
)

-- Load Staging
insert into #StagingTable (id, name, team, preferences, hashbytes_Value)
select id = 1, name = 'archibald', team = 'team 1', preferences = 'Throwaway String', hashbytes_value = hashbytes('sha1', (select team = 'team 1', name = 'archibald' for xml raw))
union select id = 2, name = 'dave',  team = 'team 1', preferences = 'Throwaway String', hashbytes_value = hashbytes('sha1', (select team = 'team 1', name = 'dave' for xml raw))
union select id = 3, name = 'peter', team = 'team 2', preferences = 'Throwaway String', hashbytes_value = hashbytes('sha1', (select team = 'team 2', name = 'peter' for xml raw))
union select id = 4, name = 'roger', team = 'team 2', preferences = 'Throwaway String', hashbytes_value = hashbytes('sha1', (select team = 'team 2', name = 'roger' for xml raw))

-- scd merge 
insert into #PresTable (id, name, team, preferences, hashbytes_Value)
select id, name, team, preferences, hashbytes_Value 
from
(
merge into #PresTable as tgt
using
(
select
    id
    ,name
    ,team
    ,preferences
    ,hashbytes_value
from
    #StagingTable
) as src
-- alias
(id, name, team, preferences, hashbytes_Value)
on src.id = tgt.id
-- must be most recent row
and tgt.row_current_ind = 1
when matched
and tgt.hashbytes_value <> src.hashbytes_value
then
update 
set 
    tgt.row_current_ind = 0
    ,row_expiry_date = sysdatetime()
when not matched
then 
insert
(
    id
    ,name
    ,team
    ,preferences
    ,hashbytes_Value
)
values
(
    src.id
    ,src.name
    ,src.team
    ,src.preferences
    ,src.hashbytes_value
)
output
    $action
    ,src.id
    ,src.name
    ,src.team
    ,src.preferences
    ,src.hashbytes_value
)
as changes
(
    action
    ,id
    ,name
    ,team
    ,preferences
    ,hashbytes_Value
) where action = 'update'

truncate table #StagingTable
insert into #StagingTable (id, name, team, preferences, hashbytes_Value)
select id = 1, name = 'archibald', team = 'team 1', preferences = 'Updated Throwaway String', hashbytes_value = hashbytes('sha1', (select team = 'team 1', name = 'archibald' for xml raw))
union select id = 3, name = 'peter', team = 'team 1', preferences = 'Updated Throwaway String',  hashbytes_value = hashbytes('sha1', (select team = 'team 1', name = 'peter' for xml raw))
union select id = 5, name = 'russell', team = 'team 2', preferences = 'Updated Throwaway String', hashbytes_value = hashbytes('sha1', (select team = 'team 2', name = 'roger' for xml raw))


-- scd merge 
insert into #PresTable (id, name, team, preferences, hashbytes_Value)
select id, name, team, preferences, hashbytes_Value 
from
(
merge into #PresTable as tgt
using
(
select
    id
    ,name
    ,team
    ,preferences
    ,hashbytes_value
from
    #StagingTable
) as src
-- alias
(id, name, team, preferences, hashbytes_Value)
on src.id = tgt.id
-- must be most recent row
and tgt.row_current_ind = 1
when matched
and tgt.hashbytes_value <> src.hashbytes_value
then
update 
set 
    tgt.row_current_ind = 0
    ,row_expiry_date = sysdatetime()
when not matched
then 
insert
(
    id
    ,name
    ,team
    ,preferences
    ,hashbytes_Value
)
values
(
    src.id
    ,src.name
    ,src.team
    ,src.preferences
    ,src.hashbytes_value
)
output
    $action
    ,src.id
    ,src.name
    ,src.team
    ,src.preferences
    ,src.hashbytes_value
)
as changes
(
    action
    ,id
    ,name
    ,team
    ,preferences
    ,hashbytes_Value
) where action = 'update'




select * from #PresTable

最终输出应如您所见,但首选项应为“更新的一次性字符串”,其中 id = 1。

这可能在同一个合并语句中吗?还是在运行合并语句之前/之后需要更新?

帖子被某人编辑了,但这是我最后想看到的示例:



UPDATE TGT
SET
    TGT.preferences = SRC.preferences
FROM 
    #PresTable TGT
INNER JOIN 
    #StagingTable SRC
    ON SRC.id = TGT.id
WHERE 1=1
    AND TGT.hashbytes_Value = SRC.hashbytes_Value

select * from #PresTable

谢谢。

【问题讨论】:

  • 抱歉,如果格式不好,我把这个放在一起举个例子。

标签: sql-server tsql scd


【解决方案1】:

MERGE 文档说(强调我的):

当匹配时然后合并匹配

指定 *target_table 的所有行,匹配的行 由 ON 返回,并满足 任何额外的搜索条件,要么更新要么删除 根据条款。

MERGE 语句最多可以有两个 WHEN MATCHED 子句。如果 指定了两个子句,第一个子句必须附有 AND 子句。对于任何给定的行,第二个 WHEN MATCHED 子句仅在第一个不是时才应用。 如果有两个 WHEN MATCHED 子句,一个必须指定一个 UPDATE 动作,一个必须 指定 DELETE 操作。当 UPDATE 在 子句,并且多于一排 基于 SQL 匹配 target_table 中的一行 服务器返回错误。 MERGE 语句不能更新同一行 不止一次,或者更新和删除同一行。

因此,您不能在匹配条件下发出 2 个不同的 UPDATE。如果您的条件不适用,您可以使用 1 UPDATE 并有条件地将列更新为新值或其当前值:

WHEN MATCHED THEN UPDATE TableName SET
    Column1 = CASE WHEN tgt.HashBytes_Value <> src.HashBytes_Value THEN UpdatedColumn1 ELSE Column1 END,
    Column2 = CASE WHEN tgt.HashBytes_Value <> src.HashBytes_Value THEN UpdatedColumn2 ELSE Column2 END,
    Column3 = CASE WHEN tgt.HashBytes_Value <> src.HashBytes_Value THEN Column3 ELSE UpdatedColumn3 END

请记住,对于实际上可能没有“更新”的行将调用触发器。

【讨论】:

  • 感谢您的回复。这种方法对我有用,问题是我输出更新步骤以向 SCD 插入新行 - 我不确定如何过滤掉 HashBytes_Value 相等的值。
  • 你不能。之后插入并删除它(这很糟糕)或删除合并语句并在多个语句中执行操作,并使用事务。当合并开始变得庞大或复杂时,我总是发现拆分它们会更好。
  • 好的,谢谢。我将在合并后添加一条更新语句,并将它们包装在一个事务中。但是问题是,如果我将它包装在事务中,我是否会阻止 PowerBI 实例在提交之前使用事务锁来读取表?
  • 加一个表示“在一个事务中执行多个语句中的操作”。自从我第一次从 Bertrand 先生那里读到 Use Caution with SQL Server's MERGE Statement 时,我就回避了 MERGE
猜你喜欢
  • 2011-02-22
  • 1970-01-01
  • 2014-10-26
  • 2019-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多