sql >> データベース >  >> RDS >> Sqlserver

トリガーでの更新操作のロギング

    答える前に、すべてのテーブルを単一のテーブルに記録するのが最善だとは思わないことを最初に言わせてください。データベースが大きくなると、ログ テーブルで深刻な競合が発生する可能性があります。さらに、同じ列に配置するには、すべてのデータを varchar または sql_variant に変更する必要があり、より多くのスペースを必要とします。また、更新された各列を別々の行に記録する (更新されていない列をスキップする) と、非常に あなたがクエリするのは難しいです。そのすべてのデータをまとめて、各行の変更、いつ、誰による変更の複合的で適切なビューを実際に取得する方法を知っていますか?私の意見では、テーブルごとに 1 つのログ テーブルを持つことは、はるかに簡単になるでしょう。そうすれば、それを機能させようとして経験している問題はなくなります。

    また、SQL Server 2008 についてもご存知でしたか?変更データ キャプチャ ? SQL Server の Enterprise または Developer エディションを使用している場合は、代わりにそれを使用してください!

    その問題とは別に、論理的な UNPIVOT (独自のバージョンを実行する) を使用して、必要なことを行うことができます。ターゲット列が 1 つではなく 2 つあるため、ネイティブ SQL 2005 UNPIVOT を実際に使用することはできません。 CROSS APPLY を使用して UNPIVOT を実行する SQL Server 2005 以降の例を次に示します。

    INSERT INTO dbo.LOG (Id_Table, Table_Key_Value, Id_Value, Old_Value, New_Value)
    SELECT 12345, I.Id, X.Id_Value, X.Old_Value, X.New_Value
    FROM
       INSERTED I 
       INNER JOIN DELETED D ON I.ID = D.ID
       CROSS APPLY (
          SELECT 4556645, D.Name, I.Name
          UNION ALL SELECT 544589, D.Surname, I.Surname
        ) X (Id_Value, Old_Value, New_Value)
    WHERE
       X.Old_Value <> X.New_Value
    

    SQL 2000 またはその他の DBMS 向けのより一般的な方法を次に示します (理論的には、Oracle、MySQL などで動作するはずです。--Oracle の場合は FROM DUAL を追加します)。 派生テーブルの各 SELECT に):

    INSERT INTO dbo.LOG (Id_Table, Table_Key_Value, Id_Value, Old_Value, New_Value)
    SELECT *
    FROM (
       SELECT
          12345,
          I.Id,
          X.Id_Value,
          CASE X.Id_Value
             WHEN 4556645 THEN D.Name
             WHEN 544589 THEN D.Surname
          END Old_Value,
          CASE X.Id_Value
             WHEN 4556645 THEN I.Name
             WHEN 544589 THEN I.Surname
          END New_Value   
       FROM
          INSERTED I 
          INNER JOIN DELETED D ON I.ID = D.ID
          CROSS JOIN (
             SELECT 4556645
             UNION ALL SELECT 544589
          ) X (Id_Value)
    ) Y
    WHERE
       Y.Old_Value <> Y.New_Value
    

    SQL Server 2005 以降にはネイティブの UNPIVOT コマンドがありますが、一般に、UNPIVOT が機能する場合でも、代わりに CROSS APPLY を使用するのが好きです。具体的には、UNPIVOT は 1 つの宛先列しかターゲットにできないため、ネイティブの UNPIVOT コマンドはここでは機能しませんが、2 つ (Old_Value、New_Value) が必要です。 2 つの列を 1 つの値に連結する (後で分離する) のは適切ではありません。後でPIVOTに無意味な行相関値を作成するのは良くありません。これら2つのバリエーションではない別の方法は考えられません。 CROSS APPLY ソリューションは、あなたが説明した正確なログ テーブル構造に一致させるには、本当に最適です。

    ここでの私のクエリと比較すると、あなたの方法 #1 はうまく機能しません (約 {列の数}:1 の比率でパフォーマンスが低下します)。あなたの方法 #2 は良いアイデアですが、UDF の呼び出しには大きなオーバーヘッドがあり、さらに各行をループする必要があるため (身震いする)、最適とは言えません。




    1. psqlの戻り値/それを呼び出したシェルスクリプトを強制終了するエラー?

    2. 'altertablerename'と'renametable'の違いは何ですか?

    3. IRIWorkbenchでの新しいテーブルの作成

    4. SQLServerの複雑さを軽減するためのヒント