2017-04-05 5 views
0

このプロジェクトでは、すべてのテーブルにオリジナルのものと同じように見えるが、[HistId]、[ActionUser]、[ActionCode ]、[ActionDate]、[ValidUntil] 基本的には、挿入、更新、削除ごとにログのようなものを作成します。その後、ユーザーが何をしたのか、誰が何をしたのか、そしていつ行ったのかをわかりやすく表示できます。変更された列のレコードのみをSQLテーブルに表示

here

問題は、データ履歴が表示されている方法ですが、それがどのように見えるかを参照してください。私はそれが基本的にすべて選択されて使用され、すべてがExcelスプレッドシートのように表示されていることがわかります。 変更されたものと見つからないものを見つけることは非常に困難です。ほとんどの場合、変更は一度に1列になります。特定のものを見つけようとするときには、必要な情報を見ることが難しいです。

私は別のアプローチをとっていました。 私は、ログのように見えるものに変更されたものだけを表示したいと思います。 、私はどちらか1つのレコードを持つように考えていた6日にあった変化(タイトルと説明)については

Record with title "a" inserted by albert on 2010-01-01 

Record's Title was updated from "a" to "b" by john on 2010-01-02 

Record's Title was updated from "b" to "c" by dave on 2010-01-03 

Record's Description was updated from "abc" to "def" by paul on 2010-01-04 

...etc... 

Record was deleted by bin on 2010-01-08 

それは次のようになり道を(私はまた後でこれが検索可能になるだろう)いずれか2つのレコードのいずれかがより複雑である。 だから基本的に私は、レコードのセットからのみ変更データを表示するために、方法を探しています、他には何も

追加情報:

  1. 履歴テーブル-sの構造は理由があり、変更することはできませんこのようなテーブルがたくさんあります。

  2. データの取得方法を変更したいと思います。

  3. 20+列

  4. を持つテーブルがあり3000万レコードを持つテーブルがあるので、パフォーマンスが重要であるが、通常は表示された、あまりにも多くのデータがありませんが、私は50のレコードの最大を言うでしょうがあります)

  5. 「から」両方持つとすべての行で、素敵に見える「する」、それはあまりにも複雑であれば、十分に

答えて

1

仮定 i)履歴表は何らかの理由で変更されません。

ii)一度に50,100,150件のレコードを表示するので、100万件を超えるレコードは問題にはなりません。

、これを試してみて、私に知らせて

create table #side ([Id] [int] IDENTITY NOT NULL, 
       [Title] [varchar](50) NOT NULL, 
       [Description] [varchar](250) NULL) 

create table #h ([HistId] [int] IDENTITY(1,1) NOT NULL, 
       [Id] [int] NOT NULL, 
       [Title] [varchar](50) NOT NULL, 
       [Description] [varchar](250) NULL, 
       [TypeId] [int] NULL, 
       [ActionUser] [int] NULL, 
       [ActionCode] [char](1) NOT NULL, 
       [ActionDate] [datetime] NOT NULL, 
       [ValidUntil] [datetime] NULL) 

insert into #side ([Title],[Description]) values ('a','abc') 

insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'a','abc',123,991,'i','01/01/2010',NULL) 

declare @mod datetime; 
set @mod = '01/02/2010' 

insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'b','abc',123,991,'u',@mod,NULL) 


insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'c','abc',123,991,'u',@mod,NULL) 

insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'c','def',123,991,'u',@mod,NULL) 

insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'d','pqr',123,991,'u',@mod,NULL) 
select * from #h order by HistId Desc 
--select * from #side 

select h.HistId, case when h.ActionCode='i' THEN 
'Record with Title "'+h.title+'" inserted ' 
when h.ActionCode='u' THEN 
'Records '+ case 
when h.title<>h1.title and h.[Description]<>h1.[Description] then 'Title,Description was updated from 
"'+h1.title+'","'+h1.[Description]+'" to " '+h.title+' " , "'+h.[Description]+'" respectively' 
when h.title<>h1.title then 'Title was updated from "'+h1.title+'" to " '+h.title+' " ' 
when h.[Description]<>h1.[Description] then 'Description was updated from "'+h1.[Description]+'" to " '+h.[Description]+' " ' 
else '' end 
when h.ActionCode='d' THEN 
'Record was deleted' 
else 
null 
END 
+'by '+cast(h.ActionUser as varchar)+' on '+convert(varchar(10),h.actiondate ,120)+'' 
from #h h 
left join #h h1 
on h.HistId=(h1.HistId+1) 
--left join #usertable u 
--on u.userid=h.[ActionUser] 

drop table #h 
drop table #side 
0

これはA使用する簡単なアプローチ、あるある「に」 self-join各レコードを前のエントリと比較します。このテクニックは、HistIdが連続した整数のシーケンスであることを前提としています。

/* Change detection, using self join. 
* See also: https://msdn.microsoft.com/en-us/library/ms177490.aspx 
*/ 
SELECT 
    CASE 
     WHEN h2.Title IS NULL THEN 'New Title: ' + h1.Title + '. ' 
     WHEN h1.Title <> h2.Title THEN 'Title updated from ' + h2.Title + ' to ' + h1.Title + '. ' 
     ELSE '' 
    END 
    + 
    CASE 
     WHEN h2.[Description] IS NULL THEN 'New Description: ' + h1.[Description] + '. ' 
     WHEN h1.[Description] <> h2.Title THEN 'Description updated from ' + h2.[Description] + ' to ' + h1.[Description] + '. ' 
     ELSE '' 
    END 
FROM 
    @SampleHistory AS h1 
     LEFT OUTER JOIN @SampleHistory AS h2   ON h2.HistoryId = (h1.HistoryId - 1) 
; 

サンプルデータ

/* Sample data. 
* Three records are created. 
* The first is a base line. 
* The next two are updates. 
* Update one contains one change. 
* Update two contains two changes. 
* 
* See also: http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-query 
*/ 
DECLARE @SampleHistory TABLE 
(
    HistoryId  INT IDENTITY(1, 1), 
    Title   VARCHAR(255), 
    [Description] VARCHAR(255) 
) 


INSERT INTO @SampleHistory 
(
    Title, 
    [Description] 
) 
VALUES 
    ('Data Warehouse Toolkit', 'First Edition'),   -- Base record. 
    ('Data Warehouse Toolkit', 'Second Edition'),   -- Description changed. 
    ('The Data Warehouse Toolkit', 'Third Edition')   -- Name and description changed. 
; 

クエリは、このアプローチの欠点は、あなたがすべての履歴テーブルにすべてのフィールドのためのケース式を記述する必要があります。良くない。この入力をすべて避ける方法の1つは、dynamic SQLです。しかし、それは複雑になることができます!

最終的な考え

私はSQLは、このようなタスクに適していないと思います。セットベースの性質のため、フィールドをループし条件付きで値を返すには多くの労力が必要です。 C#、Javaなどで、同じ結果を得ることができます。

SQL Server 2016には、すべてのエディションで、Change Data Captureが含まれています。 CDCは、SQL Server 2008,2002および2014 EnterpriseおよびDeveloperエディションに含まれています。可能であれば;私はネイティブな機能を使いたいと思っています。手作業で解決するには管理が必要であり、しばしば開発者が追加した高度な機能が欠けています。

関連する問題