1

編集:-同様の問題を抱えている人のために、ここにさまざまな解決策をカバーする良い記事があります

次のテーブル recs と audit を考えると、SQL ではどのように結果のテーブルに変換されるでしょうか。

少し背景を説明すると、前のテーブルは、データを収集する CRUD アプリケーションで使用される標準 SQL テーブルの単純化された例です。列が更新されると、レコードが 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 列 1 列 2 sys_updated_on
1 AB 2012/10/31 22:00:00
2 CD 2012/10/31 22:30:00
監査                   

ID recs_id フィールド名 old_value new_value sys_updated_on
1 1 列 1 ZA 31/10/2012 22:00:00
2 2 列 2 XD 2012 年 10 月 31 日 22:30:00
3 1 列 1 YZ 31/10/2012 21:00:00

望ましい結果

           
recs_id sys_updated_on 列 1 列 2
1ヌルYB
1 2012 年 10 月 31 日 21:00:00 ZB
1 2012 年 10 月 31 日 22:00:00 AB
2ヌルCX
2 2012/10/31 22:30:00 CD

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 に答える