1

编辑:- 对于任何有类似问题的人,这里有一篇很好的文章涵盖了各种解决方案

给定以下表 recs 和 audit,SQL 中的一个如何转换为结果表。

一点背景知识,前一个表是标准 SQL 表的简化示例,用于 CRUD 应用程序收集数据。在对列进行任何更新时,一条记录都会以 EAV 形式写入审计表。现在需要将 recs 表转换为历史表,其中包含每行的副本,因为它在报告的时间点(数据最终将存储在星型模式数据仓库中。

看起来这在程序语言中足够简单,并且使用游标可以管理(如果丑陋),但是是否有一种基于集合的方法可以工作?

我现在正在使用 T-SQL,但我想我可以从任何足够丰富的 SQL 方言中移植任何示例或想法。

设置

create table recs
(
    ID int identity(1,1) not null primary key,
    Column1 nvarchar(30) not null,
    Column2 nvarchar(30) not null,
    sys_updated_on datetime not null
)

create table audit
(
    ID int identity(1,1) not null primary key,
    recs_id int not null,
    fieldname nvarchar(30) not null,
    old_value nvarchar(30) not null,
    new_value nvarchar(30) not null,
    sys_updated_on datetime not null
)

insert into recs (Column1, Column2, sys_updated_on)
values ('A', 'B', '2012-10-31 22:00')
    , ('C', 'D', '2012-10-31 22:30')

insert into audit (recs_id, fieldname, old_value, new_value, sys_updated_on)
values (1, 'Column1', 'Z', 'A', '2012-10-31 22:00')
    , (2, 'Column2','X', 'D', '2012-10-31 22:30')
    , (1, 'Column1', 'Y', 'Z', '2012-10-31 21:00')

结果数据

记录            

ID Column1 Column2 sys_updated_on
1 AB 2012 年 10 月 31 日 22:00:00
2 光盘 2012 年 10 月 31 日 22:30:00
审计                   

ID recs_id 字段名 old_value new_value sys_updated_on
1 1 列 1 ZA 2012 年 10 月 31 日 22:00:00
2 2 列 2 XD 31/10/2012 22:30:00
3 1 Column1 YZ 31/10/2012 21:00:00

期望的结果

           
recs_id sys_updated_on Column1 Column2
1 空 YB
1 2012 年 10 月 31 日 21:00:00 中币
1 2012 年 10 月 31 日 22:00:00
2 空 CX
2 2012 年 10 月 31 日 22:30:00 光盘

4

1 回答 1

2

有趣的....

试试这个

;with cte as
(   
    select recs_id, sys_updated_on, column1, column2, 
        ROW_NUMBER() over (order by sys_updated_on) rn
    from audit a
    pivot 
        (max(old_value) for fieldname in (column1,column2)) p
)
select 
    recs_id,
    case when ud1>ud2 then ud1 else ud2 end as updateddate,
    coalesce(cte.column1,mc1,recs.column1),
    coalesce(cte.column2,mc2,recs.column2)
from cte
    outer apply 
        (
        select top 1 
            column1 as mc1, sys_updated_on as ud1 
        from cte prev1 
        where prev1.recs_id=cte.recs_id and prev1.rn<cte.rn 
        order by prev1.rn desc
        ) r1
    outer apply 
        (
        select top 1 
            column2 as mc2, sys_updated_on as ud2 
        from cte prev2 
        where prev2.recs_id=cte.recs_id and prev2.rn<cte.rn 
        order by prev2.rn desc
        ) r2
    inner join recs on cte.recs_id = recs.id
where cte.sys_updated_on is not null
union
    select id, sys_updated_on, Column1, Column2 from recs
order by recs_id, cte.updateddate   
于 2012-11-07T14:44:21.463 回答