2009-04-13 151 views
1

我想要做的是找出哪些字段已更新並將更改記錄到不同的表中。基於觸發器的歷史記錄

DECLARE 
    @BillNo int, 
    @column_name varchar(500) 

SELECT @BillNo = BillNo FROM INSERTED 
DECLARE HistoryMonitorLoop CURSOR FOR 
    SELECT  
     column_name 
    FROM 
     information_schema.columns 
    WHERE 
     table_name = 'Shipment'; 
OPEN HistoryMonitorLoop 
FETCH next FROM HistoryMonitorLoop INTO @column_name 
WHILE @@Fetch_status = 0 
BEGIN 
    DECLARE 
     @OldValue varchar(500), 
     @NewValue varchar(500) 
    SET @OldValue = (SELECT @column_name FROM Deleted); 
    SET @NewValue = (SELECT @column_name FROM Inserted); 
    IF(@OldValue != @NewValue) 
    BEGIN 
     DECLARE @Comment varchar(5000) 
     SELECT @Comment = @column_name + ' Changed from ' + @OldValue + ' to ' + @NewValue 
     EXEC ShipmentNote_Insert @[email protected],@CoordinatorID=1,@[email protected] 
    END 
    FETCH next FROM HistoryMonitorLoop INTO @column_name 
END 
CLOSE HistoryMonitorLoop 
DEALLOCATE HistoryMonitorLoop 

正在發生的事情是

SET @OldValue = (SELECT @column_name FROM Deleted); 
SET @NewValue = (SELECT @column_name FROM Inserted); 

被設置@OldValue@NewValue =的列名,而不是列的值 - SQL處理它作爲SET @OldValue = (SELECT 'column_name' FROM Deleted);

+0

那麼,腳本是否正常工作?你有錯誤嗎?你是否在測試之前問它是否好像? – BradC 2009-04-13 22:59:21

+0

和?,最新的問題是什麼? – 2009-04-13 23:24:00

+0

正在發生的事是 SET @OldValue =(SELECT @column_name FROM Deleted); SET @NewValue =(SELECT @column_name FROM Inserted); 正在將@OldValue和@NewValue =設置爲列名,而不是列的值 – 2009-04-13 23:35:39

回答

0

這不會工作:

SET @OldValue = (SELECT @column_name FROM Deleted); 
SET @NewValue = (SELECT @column_name FROM Inserted); 

你正在嘗試動態SQL,這是行不通的。您必須對SQL進行硬編碼,變量@column_name將不會被其值動態替換,因爲在觸發器運行之前觸發器的SQL會被解析一次。有了這個,你將(取決於你的設置)可能獲得列名的字面值。

可能(通過創建一個準備好的聲明中通過連接到服務器在另一個進程中,或在MySQL),以獲得動態SQL,但是這是不可能做到這一點參考「神奇」 INSERTEDDELETED觸發器中可用的僞表。

因此,您聰明地使用information_schema.columns將無法正常工作。你所能做的就是利用這種巧妙的方式編寫一個存儲過程來生成觸發器(事實上,當我必須編寫審計觸發器時,這是我做的)。然後,無論何時更改Shipment表,都必須運行sp以生成「create trigger ....」statmentnt,然後運行生成語句以重新創建觸發器。

3

我所試圖做的是找出哪些領域進行了更新

在SQL Server中有兩種功能,做你正在尋找什麼。

  • Columns_Updated() - 檢查是否一個或多個列(或多個)/插入/觸發
  • 內刪除
  • Update() - 檢查單個列被觸發內更新
0

我會重新考慮你的整個過程。如果書寫不當,觸發器可能會是巨大的性能殺手。任何時候你認爲你需要使用遊標或循環,再想一想。你需要以基於集合的方式來做到這一點。

我們使用兩表觸發器方法。一個記錄有關何時和誰更改表的詳細信息以及包含已更改信息的相關表。這有助於我們查看一次更改過的所有記錄。我們用一個更新語句的每個字段來填充第二個表是這樣的:

if (update([test])) 
    begin 
    insert [myAudit].dbo.[mytableAuditLogDetail](AuditLogID, ID, ColumnName, 
               OldValue, NewValue) 
    select 
     @AuditLogID, 
     i.[mytableid]), 
     'test', 
     convert(varchar(8000), d.[test], 0), 
     convert(varchar(8000), i.[test], 0) 
    from inserted i 
    inner join deleted d on i.[mytableid]=d.[mytableid] 
     and (
     (i.[test] <> d.[test]) or 
     (i.[test] is null and d.[test] Is Not Null) or 
     (i.[test] is not null and d.[test] Is Null) 
     )   
    end 

我們動態架構更改每次重建觸發代碼,但觸發本身不是動態的。即使我們進行大量進口時,我們的觸發程序運行也非常快。

相關問題