2008-11-18 82 views
9

我的任務是開發跟蹤數據庫更改的解決方案。跟蹤SQL Server 2005數據庫中的更改

對於更新我需要捕獲:更新

  • 舊值
  • 新的價值
  • 場影響
  • 人做變化
  • 記錄ID
    • 日期記錄在

    對於刪除:

    • 刪除
    • 人做的日期刪除
    • 標題/描述/記錄的刪除ID。我正在跟蹤的表格變更都有標題或說明字段。我想在記錄被刪除之前捕獲它。
    • 表記錄是

    對於插入:

    • 插入日期
    • 人做變化
    • 記錄ID
    • 表記錄是

    我我想到了一些方法這:

    • 我正在使用存儲過程的任何更新/刪除/插入。我會創建一個通用的「跟蹤」表。它將有足夠的字段來捕獲所有數據。然後,我會在每個存儲過程中添加另一行,以便將「將記錄插入到跟蹤表」中。
      • 缺點:所有更新/刪除/插入都在同一個表混亂
      • 很多歸零領域
      • 如何跟蹤批量更新/刪除/插入的? < ----這可能不是問題。我在應用程序中並沒有真的做過這樣的事情。
      • 如何捕獲進行更新的用戶。數據庫只看到一個帳戶。
      • 編輯大量現有代碼進行編輯。
    • 最後,我可以創建一個在更新/刪除/插入後調用的觸發器。許多與第一種解決方案相同的缺點除外:我將不得不編輯儘可能多的代碼。我不知道如何跟蹤更新。看起來好像沒有辦法使用觸發器來查看最近更新的記錄。

    我正在使用asp.net,C#,sql server 2005,iis6,windows 2003.我沒有預算,所以我不能買任何東西來幫助我。

    感謝您的回答!

  • 回答

    4

    觸發器不會有你需要一堆理由的所有信息 - 但沒有用戶ID是硬道理。

    我會說你在正確的軌道上有一個普通的sp插入任何改變的地方。如果你正在爲你的界面標準化sp,那麼你就在遊戲的前面 - 很難偷偷摸摸地追蹤那些未被追蹤的變化。

    將此視爲相當於會計應用程序中的審計跟蹤 - 這是日記帳 - 記錄每項交易的單個表。他們不會爲存款,取款,調整等實施單獨的期刊,這是相同的原則。

    4

    我討厭這個問題,並且我知道你沒有預算,但最簡單的解決方案是升級到SQL Server 2008.它具有此功能built in。我認爲至少應該提及任何遇到這個問題的人,即使你自己不能使用它。

    (在SQL 2008的部署版本,此功能僅適用於企業使用。)

    +0

    我看不出它抓住了用戶ID - 它必須是因爲已登錄的地方注入在用戶數據庫中不匹配。 – dkretz 2008-11-18 20:17:37

    1

    我看到這種處理方式的一種方式(雖然我不會推薦它),但通過存儲過程來處理它,傳遞用戶ID /用戶名/無論作爲參數。存儲過程將調用一個日誌記錄過程,該過程將相關詳細信息寫入中央日誌表中。

    這裏就是它變得有點古怪,但...

    對於插入/更新,相關行(S)被存儲在表中作爲XML數據一旦INSERT/UPDATE已成功完成。對於DELETE,該行在DELETE運行之前被存儲(儘管實際上它們可以從DELETE語句的輸出中獲得 - 至少在SQL Server 2005中)。

    如果我沒有記錯,該表只有幾列:用戶ID,日誌記錄的日期時間,事務類型(I/U/D),包含相關行的XML數據,表名和主鍵值用於快速搜索他們想要的記錄)。

    許多方法對皮膚一隻貓,但...

    我的建議是保持簡單。如果/需要的話,稍後展開。

    如果您有能力這樣做,鎖定用戶只能通過存儲過程在表上執行可操作的語句,然後從那裏處理日誌記錄(無論您想要)。

    0

    我們建立了自己的,只需要用戶和電腦傳遞到每個添加/更新存儲過程。那麼這只是獲取原始記錄和填充變量並將它們與傳入的變量進行比較並將數據記錄到我們的表中的問題。 刪除我們只是有一個副本的始發表+時間戳字段,所以記錄從來沒有真正刪除,並可以在我們需要的任何時候恢復(顯然刪除例程檢查FK關係等)。

    添加/更新日誌表看起來像 日期時間, TABLE_NAME, 列名, RECORD_ID, OLD_VALUE, NEW_VALUE, USER_ID, 計算機

    我們從來沒有插入空值,所以我們將它們轉換爲空字符串,新條目在old_value列中標記爲「{新條目}」。 RECORD_ID是由許多鍵列的唯一地標識一個記錄(字段1 +「」 +域2 + ...)

    0

    首先,在所有的表,你應該至少有這些列添加到數據列DateCreated,UserCreated,DateModified,UserModified。可能您可能需要添加「狀態」或「LastAction」列,以便您實際上不會刪除一行,而只是將其設置爲已刪除/已插入/已更新的狀態。接下來,您可以創建一個「歷史記錄表」,它是第一個表的精確副本。然後,在任何更新或刪除操作中,觸發器都會將Deleted表條目複製到History表中,同時更改DateModified,UserModified和Status字段。

    0

    我已經在SQL Server中的設置,其中我們將使用視圖來訪問我們的數據,這將處理插入,更新和使用INSTEAD OF觸發器刪除。

    例如:一個INSTEAD OF DELETE觸發器上的視圖會將底層表中的記錄標記爲已刪除,並將視圖過濾爲不顯示已刪除的記錄。

    在所有觸發器中,我們更新了修改日期和用戶名。問題在於它記錄了數據庫用戶名,這與最終的應用程序用戶名不同。

    視圖需要模式綁定才能工作。

    0

    關於更改DB的日誌記錄用戶:您可以根據需要爲數據庫創建儘可能多的SQL用戶,並且如果您使用會話和限制/註冊訪問您的程序/腳本 ,則可以使用該信息啓動不同的數據庫連接在使用數據庫進行任何操作之前設置(即用戶名), 。

    至少應該可以做PHP明智的腳本,但我可能是錯誤的asp.net。

    3

    我建議你在每張表中使用2列。名稱rowhistoryIsDeleted和數據類型將xml和位。 永遠不要刪除行,總是使用標誌IsDeleted 現在去更新觸發器。我會給你比如對同一 我有這叫做頁

    CREATE TABLE te_Page([Id] [int] IDENTITY(1,1) NOT NULL, [Name] [varchar](200) NOT NULL, [Description] [varchar](200) NULL,[CreatedBy] [uniqueidentifier] NULL, [CreatedDate] [datetime] NOT NULL, [UpdatedBy] [uniqueidentifier] NULL, [UpdatedDate] [datetime] NULL, [IsDeleted] [bit] NULL, [RowHistory] [xml] NULL, CONSTRAINT [PK_tm_Page] PRIMARY KEY CLUSTERED ([Id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] 
    

    一個表現在創建表,所有你需要做的就是複製粘貼下面的代碼,你的任務是爲頁表完成之後。它將開始在與舊值和新值一起更新的同一行中記錄行的歷史記錄。

       ALTER Trigger [dbo].[Trg_Te_Page]  
         On [dbo].[te_Page]     
         After Update     
         As     
         --If @@rowcount = 0 Or Update(RowHistory)  
         --Return  
    
         Declare @xml NVARCHAR(MAX)  
         Declare @currentxml NVARCHAR(MAX) 
         Declare @node NVARCHAR(MAX)  
         Declare @ishistoryexists XML  
    
         Declare @FormLineAttributeValueId int 
    
         -- new Values 
         Declare @new_Name varchar(200) 
         Declare @new_Description varchar(200) 
    
         Declare @new_CreatedBy UNIQUEIDENTIFIER  
         Declare @new_CreatedDate DATETIME  
         Declare @new_UpdatedBy UNIQUEIDENTIFIER  
         Declare @new_UpdatedDate DATETIME  
         Declare @new_IsDeleted BIT 
    
         --old values 
         Declare @old_Name varchar(200) 
         Declare @old_Description varchar(200) 
    
         Declare @old_CreatedBy UNIQUEIDENTIFIER  
         Declare @old_CreatedDate DATETIME  
         Declare @old_UpdatedBy UNIQUEIDENTIFIER  
         Declare @old_UpdatedDate DATETIME  
         Declare @old_IsDeleted BIT 
    
    
         -- declare temp fmId 
         Declare @fmId int 
         -- declare cursor 
         DECLARE curFormId cursor 
         FOR select Id from INSERTED 
         -- open cursor  
         OPEN curFormId 
         -- fetch row 
         FETCH NEXT FROM curFormId INTO @fmId 
    
         WHILE @@FETCH_STATUS = 0 
         BEGIN 
    
         Select 
         @FormLineAttributeValueId = Id, 
         @old_Name = Name, 
         @old_Description = [Description], 
    
         @old_CreatedBy = CreatedBy,  
         @old_CreatedDate =CreatedDate, 
         @old_UpdatedBy =UpdatedBy,  
         @old_UpdatedDate =UpdatedDate, 
         @old_IsDeleted = IsDeleted, 
         @currentxml = cast(RowHistory as NVARCHAR(MAX)) 
         From DELETED where [email protected] 
    
    
    
         Select  
         @new_Name = Name, 
         @new_Description = [Description], 
    
         @new_CreatedBy = CreatedBy,  
         @new_CreatedDate =CreatedDate, 
         @new_UpdatedBy =UpdatedBy,  
         @new_UpdatedDate =UpdatedDate, 
         @new_IsDeleted = IsDeleted 
         From INSERTED where [email protected] 
    
         set @old_Name = Replace(@old_Name,'&','&amp;') 
         set @old_Name = Replace(@old_Name,'>','&gt;') 
         set @old_Name = Replace(@old_Name,'<','&lt;')  
         set @old_Name = Replace(@old_Name,'"','&quot;') 
         set @old_Name = Replace(@old_Name,'''','&apos;')   
    
         set @new_Name = Replace(@new_Name,'&','&amp;')  
         set @new_Name = Replace(@new_Name,'>','&gt;') 
         set @new_Name = Replace(@new_Name,'<','&lt;')  
         set @new_Name = Replace(@new_Name,'"','&quot;') 
         set @new_Name = Replace(@new_Name,'''','&apos;') 
    
         set @old_Description = Replace(@old_Description,'&','&amp;') 
         set @old_Description = Replace(@old_Description,'>','&gt;') 
         set @old_Description = Replace(@old_Description,'<','&lt;')  
         set @old_Description = Replace(@old_Description,'"','&quot;') 
         set @old_Description = Replace(@old_Description,'''','&apos;')   
    
         set @new_Description = Replace(@new_Description,'&','&amp;')  
         set @new_Description = Replace(@new_Description,'>','&gt;') 
         set @new_Description = Replace(@new_Description,'<','&lt;')  
         set @new_Description = Replace(@new_Description,'"','&quot;') 
         set @new_Description = Replace(@new_Description,'''','&apos;') 
    
         set @xml = ''  
    
         BEGIN  
    
         -- for Name 
         If ltrim(rtrim(IsNull(@new_Name,''))) != ltrim(rtrim(IsNull(@old_Name,'')))  
         set @xml = @xml + '<ColumnInfo ColumnName="Name" OldValue="'+ @old_Name + '" NewValue="' + @new_Name + '"/>'  
    
         -- for Description 
         If ltrim(rtrim(IsNull(@new_Description,''))) != ltrim(rtrim(IsNull(@old_Description,'')))  
         set @xml = @xml + '<ColumnInfo ColumnName="Description" OldValue="'+ @old_Description + '" NewValue="' + @new_Description + '"/>'  
    
         -- CreatedDate  
         If IsNull(@new_CreatedDate,'') != IsNull(@old_CreatedDate,'') 
         set @xml = @xml + '<ColumnInfo ColumnName="CreatedDate" OldValue="'+ cast(isnull(@old_CreatedDate,'') as varchar(100)) + '" NewValue="' + cast(isnull(@new_CreatedDate,'') as varchar(100)) + '"/>'  
    
         -- CreatedBy  
         If cast(IsNull(@new_CreatedBy,'00000000-0000-0000-0000-000000000000')as varchar (36)) != cast(IsNull(@old_CreatedBy,'00000000-0000-0000-0000-000000000000')as varchar(36))  
         set @xml = @xml + '<ColumnInfo ColumnName="CreatedBy" OldValue="'+ cast(IsNull(@old_CreatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36)) + '" NewValue="' + cast(isnull(@new_CreatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36))+ 
         '"/>'  
    
         -- UpdatedDate  
         If IsNull(@new_UpdatedDate,'') != IsNull(@old_UpdatedDate,'')  
         set @xml = @xml + '<ColumnInfo ColumnName="UpdatedDate" OldValue="'+ cast(IsNull(@old_UpdatedDate,'') as varchar(100)) + '" NewValue="' + cast(IsNull(@new_UpdatedDate,'') as varchar(100)) + '"/>'  
    
         -- UpdatedBy  
         If cast(IsNull(@new_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36)) != cast(IsNull(@old_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36))  
         set @xml = @xml + '<ColumnInfo ColumnName="UpdatedBy" OldValue="'+ cast(IsNull(@old_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36)) + '" NewValue="' + cast(IsNull(@new_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36))+ 
         '"/>'  
    
         -- IsDeleted 
         If cast(IsNull(@new_IsDeleted,'') as varchar(10)) != cast(IsNull(@old_IsDeleted,'') as varchar(10))  
         set @xml = @xml + '<ColumnInfo ColumnName="IsDeleted" OldValue="'+ cast(IsNull(@old_IsDeleted,'') as varchar(10)) + '" NewValue="' + cast(IsNull(@new_IsDeleted,'') as varchar(10)) + '" />'  
    
         END  
    
         Set @xml = '<RowInfo TableName="te_Page" UpdatedBy="' + cast(IsNull(@new_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(50)) + '" UpdatedDate="' + Convert(Varchar(20),GetDate()) + '">' + @xml + '</RowInfo>'  
         Select @ishistoryexists = RowHistory From DELETED  
    
         --print @ishistoryexists 
    
    
         If @ishistoryexists is null  
         Begin  
         Set @xml = '<History>' + @xml + '</History>'  
         Update te_Page  
         Set  
         RowHistory = @xml  
         Where  
         Id = @FormLineAttributeValueId  
    
         End  
    
         Else  
         Begin  
         set @xml = REPLACE(@currentxml, '<History>', '<History>' + @xml) 
         Update te_Page 
         Set 
         RowHistory = @xml 
         Where 
         Id = @FormLineAttributeValueId  
         End 
    
    
         FETCH NEXT FROM curFormId INTO @fmId 
         END 
    
    
         CLOSE curFormId 
         DEALLOCATE curFormId 
    

    現在只要您將執行你的數據將存儲在rowhistory列的任何更新