「列を検証した後、傍受された UPDATE コマンドをサーバーに渡す」唯一の方法は、UPDATE
自分で実行することです。
オプション 1 - ロールバック
ただし、これらの列がテーブルに追加されるときに、トリガーにさらに列を追加する必要はないと言いました。したがって、無効な変更を単純にロールバックする代替オプションがあります。それは次のようになります。
CREATE TRIGGER TR_Sample_U ON dbo.Sample -- No AFTER trigger needed here!
AS
IF EXISTS ( --check for disallowed modifications
SELECT *
FROM
Inserted I
INNER JOIN Deleted D
ON I.SampleID = D.SampleID
WHERE
I.Something <> D.Something
AND I.UpdateDate = D.UpdateDate
)
ROLLBACK TRAN;
オプション 2 - トリガーで UPDATE を実行する
ただし、コミットする前に値を変更する必要があるなど、更新に実際に伴う内容をより詳細に制御する必要がある場合は、自分で更新を実行する必要があります。例えば:
CREATE TRIGGER TR_Sample_U ON dbo.Sample
INSTEAD OF UPDATE
AS
SET NOCOUNT ON;
SET XACT_ABORT ON;
UPDATE S
SET S.Value = I.Value + '+'
FROM
dbo.Sample S
INNER JOIN Inserted I
ON S.SampleID = I.SampleID
;
これはチェックを行わない簡単な例ですが、アイデアは得られます。Sample
テーブルで更新を実行すると、値が余分な+
文字を取得することがわかります。更新がインターセプトされ、Inserted
値 (更新後に提案された変更) がコミットされる前に変更されました。
実際の SQL Fiddle Demoを参照してください。
注意すべき唯一のことは、再帰です。
直接再帰
更新により、同じベース テーブルを変更する他のトリガーが実行される可能性がある場合、最大ネスト レベルに達し、トランザクション全体がロールバックされるまで、それらの間でピンポンを取得できます。そのため、トリガー間のピンポンの可能性に注意してください。
間接再帰
SQL Server ではデータベース レベルのRECURSIVE TRIGGERS
オプションが既定でオフになっているため、おそらくこれについて心配する必要はありません。ただし、オンの場合は、新しい更新に基づいて同じトリガーを起動できます。
これらは、さまざまな方法で改善されます。
トリガーの内部をチェックTRIGGER_NESTLEVEL
し、すでに十分にネストされている場合はトリガーを終了します。
直接再帰のみを回避するには、トリガーを組み合わせます。
特定のケースでは、最初/最後に実行するトリガーを戦略的に割り当てることで、問題が解決する場合があります。絶対的な順序を指定することはできませんが、最初のものと最後のものを選択できます。
ピンポン問題は、独自のベース テーブルを変更する、または最終的に発生する別のテーブル (別のテーブルを変更するトリガーを含む) を介した一連の更新に関与INSTEAD OF
する任意のタイプのトリガーに適用されることに注意してください。AFTER
元のテーブルを変更します。
オプション 2B - AFTER UPDATE トリガーを前処理します。
私はこのオプションを 2B と呼んでいます。これは実際にはオプション 2 ですが、拡張機能を備えているためです。テーブルに列を追加するたびにトリガーを手動で更新する必要がない場合 (私も完全に同意します)、これを自動化できます。必要なすべての検証を監視する適切なトリガーを作成できるストアド プロシージャを作成します。この検証の基本コードをテーブルに配置し、SP でそれを変数に選択し、INFORMATION_SCHEMA.COLUMNS
ビュー内の情報をマイニングして最終更新の列を更新する SQL スクリプトを追加し、最後にトリガーを書き直すことができます。さらに、これを DDL トリガーにアタッチして、100% 自動化することもできます。ベース テーブルに列を追加または削除すると、DDL トリガーが起動し、DML トリガーが書き換えられます。
これは大変な作業のように思えますが、データ駆動型になるように設計すると、データベース全体の任意のテーブルで動作するように一般化できるため、使用シナリオによっては非常に価値があります。