2

我已经为我正在处理的仓库实施了四个 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

谢谢你。

4

1 回答 1

1

MERGE文档说(强调我的):

当匹配然后合并匹配

指定 *target_table 中与 ON 返回的行匹配并满足任何其他搜索条件的所有行都根据该子句进行更新或删除。

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

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

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

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

于 2019-08-16T10:31:34.203 回答