2017-04-05 50 views
0

在此項目中,每個表都有一個「歷史表」,它與原始表相同,但添加了以下列:[HistId],[ActionUser],[ActionCode ],[ActionDate],[ValidUntil] 基本上每一個插入,更新,刪除,我們就像一個日誌。之後,我們很容易看到用戶做了什麼,誰做了什麼,什麼時候做了什麼。僅在SQL表中顯示已更改列的記錄

看到它的外觀,here

的問題是所顯示的數據歷史的方式。我發現它基本上是使用全選,並且所有內容都像Excel電子表格一樣顯示。 很難找到什麼變化,什麼不變。大多數情況下,這些更改一次只有一列。而當你試圖找到具體的東西時,很難看到你需要的信息。

我想使用不同的方法。 我只想顯示看起來像日誌的內容所發生的變化。 (我也想使這個搜索以後)

它看起來喜歡的方式:

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 

因爲我當時就想,要麼1分的記錄,這是6日的變化(標題和描述)或者2條記錄,以較小者爲準。 所以基本上我正在尋找一種方式,從一組記錄只顯示更改後的數據,沒有別的

額外的信息:

  1. 歷史表-S結構不能改變,因爲有有很多像這樣的表。

  2. 我想只改變我們檢索數據的方式。

  3. 有20組以上的列

  4. 有30萬條記錄表的表,這樣的表現是很重要的,但通常顯示的數據過多也不會有,我會說50個記錄最大值)

  5. 兼具「從」和「到」的每一行,看起來不錯,但如果過於複雜,那麼「到」足以

回答

1

假設 i)歷史表不會因任何原因而改變。

ii)由於您一次將顯示50,100,150條記錄,因此不會出現問題。

試試這個,讓我知道,

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

這是一個簡單的方法,即使用self-join比較每條記錄與之前的條目。該技術假設HistId是一個不間斷的整數序列。

樣本數據

/* 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. 
; 

查詢

/* 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) 
; 

這樣做的缺點的方法是你必須寫在每一個歷史表中每個字段的情況下表達。不好。避免所有這些類型的一種方法是使用dynamic SQL。但是這可能很複雜!

最後的思考

我不認爲SQL是非常適合這樣的任務。由於其基於集合的性質,循環遍歷字段並有條件地返回值需要很多努力。在C#,Java等平臺上,您可以獲得相同的結果,並且花費更少的努力。

SQL Server 2016包括Change Data Capture開箱即用的所有版本。 CDC包含在SQL Server 2008,2012和2014 Enterprise和Developer版本中。在可能的情況;我更喜歡使用本機功能。手動解決方案需要管理,並且通常缺乏開發人員添加的高級功能。

相關問題