【问题标题】:SCD Type 2 - Handling Intraday changes?SCD 类型 2 - 处理日内变化?
【发布时间】:2021-08-18 15:25:47
【问题描述】:

我有一个合并语句,每晚都会构建我的 SCD 类型 2 表。该表必须包含在源系统中所做的所有历史更改,并创建一个新行,其中包含日期从/日期到列以及“islatest”标志。我今天遇到一个问题,我不确定如何处理。

在 24 小时内似乎对源表进行了多次更改。

    ID      Code         PAN     EnterDate   Cost     Created
  16155 1012401593331   ENRD    2015-11-05  7706.3  2021-08-17 14:34
  16155 1012401593331   ENRD    2015-11-05  8584.4  2021-08-17 16:33

我使用基本的合并语句来识别我的更改,但是确保正确获取所有更改的最佳方法是什么?上面给了我一个错误,因为它试图插入/更新具有相同值的多行

DECLARE @DateNow DATETIME = Getdate()
IF Object_id('tempdb..#meteridinsert') IS NOT NULL
DROP TABLE #meteridinsert;

CREATE TABLE #meteridinsert
             (
                          meterid INT,
                          change  VARCHAR(10)
             );
             
             
             MERGE
INTO         [DIM].[Meters] AS target
using        stg_meters     AS source
ON target.[ID] = source.[ID]
AND          target.latest=1
WHEN matched THEN
UPDATE
SET              target.islatest = 0,
                 target.todate = @Datenow
WHEN NOT matched BY target THEN
INSERT
       (
              id,
              code,
              pan,
              enterdate,
              cost,
              created,
              [FromDate] ,
              [ToDate] ,
              [IsLatest]
       )
       VALUES
       (
              source.id,
              source.code ,
              source.pan ,
              source.enterdate ,
              source.cost ,
              source.created ,
              @Datenow ,
              NULL ,
              1
       )
       output source.id,
       $action
INTO   #meteridinsert;INSERT INTO [DIM].[Meters]
            (
                        [id] ,
                        [code] ,
                        [pan] ,
                        [enterdate] ,
                        [cost] ,
                        [created] ,
                        [FromDate] ,
                        [ToDate] ,
                        [IsLatest]
            )
SELECT     ([id] ,[code] ,[pan] ,[enterdate] ,[cost] ,[created] , @DateNow  ,NULL ,1 FROM stg_meters a
INNER JOIN #meteridinsert cid
ON         a.id = cid.meterid
AND        cid.change = 'UPDATE'

【问题讨论】:

  • 为什么要使用@datenow,如果你说同一个自然键有很多条记录要加载?您不需要用该自然键的下一条记录的startdate 更新todate 吗?
  • 我实际上是在遵循本指南,但我明白你在说什么(尤其是在这种情况下)使用下一条记录的开始日期purplefrogsystems.com/blog/2012/01/… 更有意义

标签: sql sql-server-2016


【解决方案1】:

也许你可以使用merge 语句来做到这一点,但我更喜欢使用典型的updateinsert 方法以便更容易理解(我也不确定merge 是否允许你使用相同的源记录进行更新和插入...)

首先我创建表dimscd2 来表示您的维度表

create table dimscd2 
(naturalkey int, descr varchar(100), startdate datetime, enddate datetime)

然后我插入一些记录...

insert into dimscd2 values
(1,'A','2019-01-12 00:00:00.000', '2020-01-01 00:00:00.000'),
(1,'B','2020-01-01 00:00:00.000', NULL)

如您所见,“当前”是带有 descr='B' 的那个,因为它有一个 enddate NULL(我建议您对每条记录使用 代理键...这个只是你维度的每条记录的增量键,事实表必须和这个代理键链接,才能反映事实发生时的状态)。

然后,我创建了一些虚拟数据来表示具有相同自然键更改的源数据

-- new data (src_data)
select 1 as naturalkey,'C' as descr, cast('2020-01-02 00:00:00.000' as datetime) as dt into src_data
union all
select 1 as naturalkey,'D' as descr, cast('2020-01-03 00:00:00.000' as datetime) as dt

之后,我使用此查询创建了一个临时表 (##tmp),为每条记录设置 enddate

-- tmp table
select naturalkey, descr, dt, 
  lead(dt,1,0) over (partition by naturalkey order by dt) enddate,
  row_number() over (partition by naturalkey order by dt) rn
into ##tmp  
from src_data 

LEAD 函数采用相同自然键的下一个开始日期,按日期排序 (dt)。 ROW_NUMBER1 标记维度中自然键的源数据中最旧的记录。

然后,我继续使用update 关闭“当前”记录

update d
set enddate = t.dt
from dimscd2 d
  join ##tmp t
    on d.naturalkey = t.naturalkey
   and d.enddate is null
   and t.rn = 1

最后我用insert将新的源数据添加到维度中

insert into dimscd2
select naturalkey, descr, dt, 
  case enddate when '1900-00-00' then null else enddate end 
from ##tmp

通过查询获得最终结果:

select * from dimscd2

你可以在这个db<>fiddle上测试

【讨论】:

  • 这是一个非常好的方法,我什至没有考虑过使用更新/插入(主要是因为当我研究实现 SCD 2 时,它要么使用 SSIS 要么使用 MERGE)谢谢你,它已经奏效了教会了我一种新方法!
  • MERGE 语句非常适合 SCD1 维度...不确定是否可以将此功能用于 SCD2 维度,因为您使用最旧的记录进行更新(enddate 用于之前的“当前") 并插入它,通常合并允许您对每条记录进行一次操作,而不是两次
猜你喜欢
  • 2021-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
相关资源
最近更新 更多