2009-04-13 18 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); 

はなく列の値のColumnNameのに= @OldValue@NewValue設定されている - SQLは、SET @OldValue = (SELECT 'column_name' FROM Deleted);

+0

スクリプトは機能していますか?エラーが出ていますか?あなたがそれをテストする前に大丈夫だと尋ねるだけですか? – BradC

+0

と?、何が質問ですか? –

+0

何が起こっているのですか? SET @OldValue =(SELECT @列名FROM Deleted); SET @NewValue =(SELECT @列名からFROM挿入); は、@ OldValueと@NewValue =をカラムの値ではなくカラム名に設定しています –

答えて

1

それは使用しています。このPop on the Audit Trailを参照してくださいチェックあなたがやりたがっていることだけを実行するために、カーソルではなくループ内のクエリ。

+0

それをした、今私がしなければならないのはどのように把握することです;) –

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テーブルを変更するたびに、 "create trigger ...."という文を生成するためにspを実行してから、を実行して、というトリガを再作成するステートメントを実行する必要があります。私がやろうとしています何

+0

ShipmentNote_Insertは、問題ではないように日付スタンプを追加します。パフォーマンスがヒットする限り、出荷テーブル自体のデータは頻繁には更新されませんが、変更されたことを知る必要がある場合は、サードパーティのアプリケーションが通知を使用します。テーブルの構造は非常に流動的です今すぐ –

+0

あなたの質問は何ですか? – tpdi

3

がSQL Serverでは

を見つける更新されたされたフィールドをあなたが探しているまさにん二つの機能があります。

  • Columns_Updated() - 一の以上の列(複数可)/トリガ
  • Update()を削除/挿入されているか確認してください - 単一の列は、トリガー内で更新される場合
0

あなたの全体のプロセスを再考したいと思います。不適切に書かれた場合、トリガーはパフォーマンスの大きな原因となります。カーソルやループを使用する必要があると思うときはいつでも、再度考えてみてください。あなたはセットベースの方法でこれを行う必要があります。

2つのテーブルトリガーアプローチを使用します。いつ誰がテーブルを変更したかについての詳細と、変更された情報を含む関連テーブルを記録するテーブル。これにより、一度に変更されたすべてのレコードが表示されます。

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 

我々は動的にスキーマを変更しましたが、トリガ自体が動的ではありませんされるたびにトリガコードを再構築:我々のような第2のテーブルに何かを移入するフィールドごとに更新ステートメントを使用します。大量輸入を行ってもトリガープロセスは非常に高速に実行されます。