根据另一个表中的信息构建对行的更改的历史跟踪

Ben*_*sen 5 sql t-sql sql-server ssis

我有一个包含公司内所有项目的表格 - 项目表格.每行代表一个项目,其中包含每个属性的最新值(例如单位价格,此项目的利润,供应商,描述等).

ItemNo | Description | Unit Price | Profit % |
----------------------------------------------
1      |  MyItem     |   200      |   47     |
2      | MyOtherItem |   300      |   25     |
Run Code Online (Sandbox Code Playgroud)

在另一个表中,我对Item-table进行了历史更改 - ChangeLog History Table它显示了ItemNo,已更改的列,旧值和新值以及显示更改发生时间的DateCreated列.像这样:

ItemNo | ColumnName  | OldValue | New Value | DateCreated |
-----------------------------------------------------------
1      |  Unit Price |    50    |   100     | 20170401    |
1      |  Unit Price |    100   |   200     | 20170501    |
2      |  Profit %   |     2    |    25     | 20170603    |
1      |  Profit %   |     99   |    47     | 20170604    |
Run Code Online (Sandbox Code Playgroud)

我想创建一个看起来像Item表的表,但是根据Changelog Hisotry表,使用ValidFrom和ValidTo Date按时间顺序跟踪所有更改.所以开头的Item-table应该如下所示:

ItemNo | Description | Unit Price | Profit % | ValidFrom  | ValidTo
-------------------------------------------------------------------
1      |  MyItem     |   200      |   47     | 2017-06-04 | 9999-12-31
1      |  MyItem     |   200      |   99     | 2017-05-01 | 2017-06-04
1      |  MyItem     |   100      |   99     | 2017-04-01 | 2017-05-01
1      |  MyItem     |   50       |   99     | 1900-01-01 | 2017-04-01
2      | MyOtherItem |   300      |   25     | 2017-06-03 | 9999-12-31
2      | MyOtherItem |   300      |   2      | 1900-01-01 | 2017-06-03
Run Code Online (Sandbox Code Playgroud)

所以问题是如何使用T-SQL创建它?我掌握了SSIS,但是我不知道如何解决这个问题,一直试图让我的头脑绕了好几个小时.

提前致谢!

Ser*_*erg 1

尝试一下这个,对于 2 列:

WITH hist AS (
  -- sample change log data
  select * 
  from (
    Values
         (1,'Unit Price',50 ,100, cast('20170401' as date))
        ,(1,'Unit Price',100,200,'20170501')
        ,(2,'Profit %', 2 , 25,'20170603')
        ,(1,'Profit %', 99, 47,'20170604') 
    ) t(ItemNo,ColumnName,OldValue,NewValue,DateCreated )
),
items AS(
  -- sample items data
  select * 
  from (
    Values
         (1, 'MyItem',211,4)
        ,(2,'MyOtherItem',311,2)
     ) t(ItemNo,Description,UnitPrice,[Profit %])
),
-- Solution
hist2 AS (
    -- Add the very old values from change log as new starting at 1900-01-01
    SELECT * 
    FROM hist
    UNION ALL
    SELECT TOP(1) WITH TIES ItemNo, ColumnName, null, OldValue, '19000101'
    FROM hist
    ORDER BY row_number() over (partition by ItemNo, ColumnName order by DateCreated)   
),    
intv AS (
    -- Get itervals from augmented change log
    SELECT ItemNo
      , sD = DateCreated
      , eD = coalesce(dateadd(day, -1, lead(DateCreated) over (partition by ItemNo order by DateCreated)),'99991231')
    FROM (
        SELECT DISTINCT ItemNo, DateCreated 
        FROM hist2
    ) t
)
-- Fill intervals with values from augmented change log, using Items values as a last resort
SELECT items.ItemNo, items.Description, Sd, Ed
  , coalesce(p1.UnitPrice, items.UnitPrice)
  , coalesce(p2.[Profit %], items.[Profit %])
FROM intv
OUTER APPLY (
    select top(1) UnitPrice = NewValue
    from hist2 h
    where h.ItemNo = intv.ItemNo and h.ColumnName = 'Unit Price' and DateCreated <= Ed
    order by DateCreated desc
    ) p1
OUTER APPLY (
    select top(1) [Profit %] = NewValue
    from hist2  h
    where h.ItemNo = intv.ItemNo and h.ColumnName = 'Profit %' and DateCreated <= Ed
    order by DateCreated desc
    ) p2 
JOIN items ON items.ItemNo = intv.ItemNo
Run Code Online (Sandbox Code Playgroud)

您可能想要实例化 hist2 并添加适当的索引以获得更好的性能。