2013-07-26 184 views
4

我有一個要求,即在有UPDATE調用時,保留對特定表所做更改的歷史記錄,但只關注特定列。SQL歷史記錄表和觸發器

所以,我創建了一個歷史記錄表:

CREATE TABLE [dbo].[SourceTable_History](
    [SourceTable_HistoryID] [int] IDENTITY(1,1) NOT NULL, 
    [SourceTableID] [int] NOT NULL, 
    [EventDate] [date] NOT NULL, 
    [EventUser] [date] NOT NULL, 
    [ChangedColumn] VARCHAR(50) NOT NULL, 
    [PreviousValue] VARCHAR(100) NULL, 
    [NewValue] VARCHAR(100) NULL 

    CONSTRAINT pk_SourceTable_History PRIMARY KEY ([SourceTable_HistoryID]), 
    CONSTRAINT fk_SourceTable_HistoryID_History_Source FOREIGN KEY ([SourceTableID]) REFERENCES SourceTable (SourceTableId) 
) 

阿卜杜勒我的計劃是建立在sourceTable會一個UPDATE觸發器。該業務只關心更改某些列,因此,在psudo代碼,我正打算這樣做

If source.Start <> new.start 
Insert into history (PrimaryKey, EventDate, EventUser, ColumnName, OldValue, NewValue) 
(PK, GETDATYE(), updateuser, "StartDate", old.value, new.value) 

而且會有這樣每列的我們要對歷史塊。

我們不允許使用CDC,所以我們必須推出我們自己的,這是我迄今的計劃。

這似乎是一個合適的計劃?

我們需要監控7個表格,每個表格的列數在2到5列之間。

我只需要弄清楚如何讓一個觸發器首先comapr特定的columnm的前後值,然後寫一個新的行。

我認爲這是簡單的東西:

CREATE TRIGGER tr_PersonInCareSupportNeeds_History 
ON PersonInCareSupportNeeds 
FOR UPDATE 
AS 
BEGIN 
    IF(inserted.StartDate <> deleted.StartDate) 
    BEGIN 
     INSERT INTO [dbo].[PersonInCareSupportNeeds_History] 
     ([PersonInCareSupportNeedsID], [EventDate], [EventUser], [ChangedColumn], [PreviousValue], [NewValue]) 
     VALUES 
     (inserted.[PersonInCareSupportNeedsID], GETDATE(), [LastUpdateUser], 'StartDate', deleted.[StartDate], deleted.[StartDate]) 
    END 
END 

回答

1

根據您的質量要求,我覺得歷史表應該反映你想要捕捉的表,再加上額外的審計細節(誰,何時,爲什麼) 。

這可以更容易地使用相同的現有邏輯(SQL,數據類,屏幕等)來查看歷史數據。

隨着您的設計獲取數據將會正常,但將數據以可用格式提取出來會有多容易?

+0

謝謝ptutt。要獲取歷史數據,對於特定的源記錄,我認爲它會是「SELECT EventUser,EventDate,ChangedColumn,OldValue,NewValue FROM History table WHERE SourceId = x」。這將允許我顯示,「在[Date]上,用戶[User]將列[ColumnChanged]從[OldValue]更改爲[New Value]。 – Craig

+0

根據您的建議,源表和歷史表之間會存在一對多關係嗎? – Mangoose

+0

@Mangus正確。歷史表可以提供數據的快照。 – ptutt

1

那麼我認爲你的想法並不是那麼糟糕。其實,我有類似的製作系統。我不會給你我完整的代碼(與歷史保存同步),但我可以給你一些指導。

主要想法是將數據從關係模型轉換爲Entity-Attribute-Value model。此外,我們希望我們的觸發器儘可能一般,這意味着 - 不要顯式地寫列名稱。這可以通過不同的方式來完成,但是最一般的,我知道在SQL Server是使用FOR XML,然後從XML選擇:

declare @Data xml 

select @Data = (select * from Test for xml raw('Data')) 

select 
    T.C.value('../@ID', 'bigint') as ID, 
    T.C.value('local-name(.)', 'nvarchar(128)') as Name, 
    T.C.value('.', 'nvarchar(max)') as Value 
from @Data.nodes('Data/@*') as T(C) 

SQL FIDDLE EXAMPLE

得到兩代表的不同行,你可以使用EXCEPT

select * from Test1 except select * from Test2 
union all 
select * from Test2 except select * from Test1 

SQL FIDDLE EXAMPLE

,最後,你的觸發可能是someth荷蘭國際集團這樣的:

create trigger utr_Test_History on Test 
after update 
as 
begin 
    declare @Data_Inserted xml, @Data_Deleted xml 

    select @Data_Inserted = 
    (
     select * 
     from (select * from inserted except select * from deleted) as a 
     for xml raw('Data') 
    ) 

    select @Data_Deleted = 
    (
     select * 
     from (select * from deleted except select * from inserted) as a 
     for xml raw('Data') 
    ) 

    ;with CTE_Inserted as (
     select 
      T.C.value('../@ID', 'bigint') as ID, 
      T.C.value('local-name(.)', 'nvarchar(128)') as Name, 
      T.C.value('.', 'nvarchar(max)') as Value 
     from @Data_Inserted.nodes('Data/@*') as T(C)  
    ), CTE_Deleted as (
     select 
      T.C.value('../@ID', 'bigint') as ID, 
      T.C.value('local-name(.)', 'nvarchar(128)') as Name, 
      T.C.value('.', 'nvarchar(max)') as Value 
     from @Data_Deleted.nodes('Data/@*') as T(C)  
    ) 
    insert into History (Table_Name, Record_ID, Event_Date, Event_User, Column_Name, Value_Old, Value_New) 
    select 'Test', isnull(I.ID, D.ID), getdate(), system_user, isnull(D.Name, I.Name), D.Value, I.Value 
    from CTE_Inserted as I 
     full outer join CTE_Deleted as D on D.ID = I.ID and D.Name = I.Name 
    where 
    not 
    (
     I.Value is null and D.Value is null or 
     I.Value is not null and D.Value is not null and I.Value = D.Value 
    ) 
end 

SQL FIDDLE EXAMPLE

2

我們有基於觸發的審覈制度,我們基本上是用於生成審計分析如何第三方工具創建它觸發ApexSQL審計創建觸發器和管理存儲,並開發了自己的系統基礎在那。

我認爲你的解決方案通常是可以的,但你需要考慮修改存儲和計劃縮放。

如果企業決定跟蹤所有表中的所有列,該怎麼辦?如果他們決定跟蹤插入和刪除呢?你的解決方案能夠適應這種情況嗎?

存儲:使用兩個表來保存您的數據。一個表用於保存有關事務的所有信息(何時,誰,應用程序名稱,表名,模式名稱,受影響的行等)。另一個表格用於保存實際數據(值前後的主鍵等)。

觸發器:我們結束了一個模板插入,更新和刪除觸發器和非常簡單的C#應用​​程序,我們輸入表和列,所以應用程序輸出DDL。這節省了我們很多時間。

相關問題