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 @BillNo=@BillNo,@CoordinatorID=1,@Comment=@Comment
    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); 

@OldValueand @NewValue= を列の値ではなく列名に設定しています – SQLはそれを次のように処理していますSET @OldValue = (SELECT 'column_name' FROM Deleted);

4

4 に答える 4

3

私がやろうとしているのは、どのフィールドが更新されたかを調べることです

SQL Serverには、探していることを正確に実行する2つの関数があります。

  • Columns_Updated() -1つ以上の列がトリガー内に挿入/削除されているかどうかを確認します
  • Update() -トリガー内で単一の列が更新されているかどうかを確認します
于 2009-04-14T02:24:32.590 に答える
1

これを参照してください監査証跡のポップ これは、カーソルではなくループでクエリを使用して、やりたいことを実行します。

于 2009-04-14T02:48:09.163 に答える
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...."ステートメントを生成し、その生成されたステートメントを実行してトリガーを再作成する必要があります。

于 2009-04-13T23:23:40.887 に答える
0

プロセス全体を再考します。トリガーは、不適切に記述された場合、パフォーマンスを大幅に低下させる可能性があります。カーソルまたはループを使用する必要があると思うときはいつでも、もう一度考え直してください。これは、セットベースの方法で行う必要があります。

2 つのテーブル トリガー アプローチを使用します。いつ、誰がテーブルを変更したかについての詳細を記録するものと、変更された情報を含む関連テーブル。これにより、一度に変更されたすべてのレコードを確認できます。各フィールドに更新されたステートメントを使用して、次のような 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

スキーマが変更されるたびにトリガー コードを動的に再構築しますが、トリガー自体は動的ではありません。大規模なインポートを行う場合でも、トリガー プロセスは非常に高速に実行されます。

于 2009-04-14T14:15:42.087 に答える