【问题标题】:Building a snapshot table from audit records从审计记录构建快照表
【发布时间】:2016-06-09 21:22:00
【问题描述】:

我有一个Customer 表,其结构如下。

CustomerId Name   Address    Phone
1          Joe    123 Main   NULL

我还有一个 Audit 表,用于跟踪对 Customer 表的更改。

Id  Entity   EntityId  Field    OldValue      NewValue     Type   AuditDate  
1   Customer 1         Name     NULL          Joe          Add    2016-01-01
2   Customer 1         Phone    NULL          567-54-3332  Add    2016-01-01
3   Customer 1         Address  NULL          456 Centre   Add    2016-01-01
4   Customer 1         Address  456 Centre    123 Main     Edit   2016-01-02
5   Customer 1         Phone    567-54-3332   843-43-1230  Edit   2016-01-03
6   Customer 1         Phone    843-43-1230   NULL         Delete 2016-01-04

我有一个 CustomerHistory 报告表,其中将填充每日 ETL 作业。它与客户表具有相同的字段,并具有附加字段SnapShotDate

我需要编写一个查询,获取Audit 表中的记录,转换并插入CustomerHistory,如下所示。

CustomerId Name   Address      Phone         SnapShotDate
1          Joe    456 Centre   567-54-3332   2016-01-01
1          Joe    123 Main     567-54-3332   2016-01-02
1          Joe    123 Main     843-43-1230   2016-01-03
1          Joe    123 Main     NULL          2016-01-04

我猜该解决方案将涉及审计表上的自联接或递归 CTE。对于开发此解决方案的任何帮助,我将不胜感激。

注意:很遗憾,我无法选择使用触发器或更改审核表架构。查询性能不是问题,因为这将是一个夜间 ETL 过程。

【问题讨论】:

  • 为了清楚起见,您已经有一个 ETL 来填充 CustomerHistory,为什么要从 Audit 表中填充它?顺便说一句,这是一个有趣的谜题:)
  • @FLICKER - 澄清一下,我需要构建一个查询来通过 ETL 过程填充 CustomerHistory 表。此时尚未填充数据。
  • 知道了。我快找到解决方案了
  • 这解决了我的问题。 sqlmag.com/t-sql/last-non-null-puzzle

标签: sql-server sql-order-by audit-trail


【解决方案1】:

您可以使用以下脚本。

DROP TABLE #tmp

CREATE TABLE #tmp (
    id INT Identity
    , EntityId INT
    , NAME VARCHAR(10)
    , Address VARCHAR(100)
    , Phone VARCHAR(20)
    , Type VARCHAR(10)
    , SnapShotDate DATETIME
    )

;with cte1 as (
select AuditDate, EntityId, Type, [Name], [Address], [Phone]
from 
    (select AuditDate, EntityId, Type, Field, NewValue from #Audit) p
pivot
    (
    max(NewValue)
    for Field in ([Name], [Address], [Phone])
    ) as xx
)
insert into #tmp (EntityId, Name, Address, Phone, Type, SnapShotDate)
select EntityId, Name, Address, Phone, Type, AuditDate
from cte1


-- update NULLs columns with the most recent value
update #tmp
set Name = (select top 1 Name from #tmp tp2 
            where EntityId = tp2.EntityId and Name  is not null 
            order by id desc)
where Name is null

update #tmp
set Address = (select top 1 Address from #tmp tp2 
               where EntityId = tp2.EntityId and Address is not null 
               order by id desc)
where Address is null

update #tmp
set Phone = (select top 1 Phone from #tmp tp2 
             where EntityId = tp2.EntityId and Phone is not null 
             order by id desc)
where Phone is null

要创建Test Data,请使用以下脚本

CREATE TABLE #Customer (
    CustomerId INT
    , NAME VARCHAR(10)
    , Address VARCHAR(100)
    , Phone VARCHAR(20)
    )

INSERT INTO #Customer
VALUES (1, 'Joe', '123 Main', NULL)

CREATE TABLE #Audit (
    Id INT
    , Entity VARCHAR(50)
    , EntityId INT
    , Field VARCHAR(20)
    , OldValue VARCHAR(100)
    , NewValue VARCHAR(100)
    , Type VARCHAR(10)
    , AuditDate DATETIME
    )

insert into #Audit values
(1,   'Customer', 1,         'Name'     ,NULL            ,'Joe'          ,'Add'    ,'2016-01-01'),
(2,   'Customer', 1,         'Phone'    ,NULL            ,'567-54-3332'  ,'Add'    ,'2016-01-01'),
(3,   'Customer', 1,         'Address'  ,NULL            ,'456 Centre'   ,'Add'    ,'2016-01-01'),
(4,   'Customer', 1,         'Address'  ,'456 Centre'    ,'123 Main'     ,'Edit'   ,'2016-01-02'),
(5,   'Customer', 1,         'Phone'    ,'567-54-3332'   ,'843-43-1230'  ,'Edit'   ,'2016-01-03'),
(6,   'Customer', 1,         'Phone'    ,'843-43-1230'   ,NULL           ,'Delete' ,'2016-01-04'),
(7,   'Customer', 2,         'Name'     ,NULL            ,'Peter'        ,'Add'    ,'2016-01-01'),
(8,   'Customer', 2,         'Phone'    ,NULL            ,'111-222-3333'  ,'Add'    ,'2016-01-01'),
(8,   'Customer', 2,         'Address'  ,NULL            ,'Parthenia'   ,'Add'    ,'2016-01-01')

结果

EntityId    Name    Address     Phone           Type    SnapShotDate
1           Joe     456 Centre  567-54-3332     Add     2016-01-01
1           Joe     123 Main    843-43-1230     Edit    2016-01-02
1           Joe     123 Main    843-43-1230     Edit    2016-01-03
1           Joe     123 Main    843-43-1230     Delete  2016-01-04

【讨论】:

  • 感谢您的回复。当我运行查询时,我得到一个不同的结果集(见下文)。它有一排给乔,剩下的给彼得,快照日期不准确。此外,该解决方案需要每个字段的更新语句。 3个字段没什么大不了的,但是当字段更多时,会有很多重复的代码。我想我们可以想出一个使用自连接(或递归 CTE)的更精简的解决方案。再次感谢您的初步努力。
  • id EntityId NAME 地址 电话类型 SnapShotDate 1 1 Joe 456 Center 567-54-3332 添加 2016-01-01 00:00:00.000 2 2 Peter Parthenia 111-222-3333 添加 2016-01- 01 00:00:00.000 3 1 彼得 123 主要 843-43-1230 编辑 2016-01-02 00:00:00.000 4 1 彼得 123 主要 843-43-1230 编辑 2016-01-03 00:00:00.000 5 1彼得 123 主要 843-43-1230 删除 2016-01-04 00:00:00.000
  • 在第一个查询中,填充临时表时,使用 ORDER BY EntityId、AuditDate。让我知道它是如何工作的
  • 或使用 ORDER BY EntityId, AuditDate。
猜你喜欢
  • 2021-04-26
  • 1970-01-01
  • 1970-01-01
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
  • 1970-01-01
相关资源
最近更新 更多