4

SQLCLR アセンブリにアフター トリガーを実装しています。その中で、どの列が実際に更新された (そしてそれらの値が変更された) かを知りたいです。

残念ながら、列の値が同じであっても、SqlContext.TriggerContext.IsUpdatedColumn は true を返します。おそらく、あまりスマートではないサーバー アプリケーションによって作成された SQL クエリが、ユーザーによって変更されていない列の一部であっても、すべての列を書き換えるからだと思います。

2 番目の問題は、一部の列に ntext 型があるため、INSERTED 疑似テーブルからそれらを SELECT することさえできません (MS SQL Server では、INSERTED から ntext 型を持つ SELECT フィールドを許可していません)。そのため、次のクエリで変更された行を SELECT します。

SELECT * FROM [dbo].[MyTable] WHERE [id] IN (SELECT [id] FROM INSERTED)

どの列が更新されただけでなく、変更されたのかを知るにはどうすればよいですか?

これで簡単なアイデアが浮かびました。BEFORE という別のトリガーを作成し、更新された行を内部から保存します。次に、AFTER トリガーが実行されているときに、列の値を比較します。このアイデアは私ができる最善のことですか?その場合、BEFORE トリガーと AFTER トリガーの間で変更された行を保持するのに最適な場所はどこですか? AFTER トリガーが実行される前に一時テーブルが削除されます。これは、コンテキスト接続を閉じるためです (おそらく、閉じないでください)。

4

1 に答える 1

2

OK、これで問題は解決しました。

まず、ソース テーブル (データ + 構造) の完全なコピーを作成しました。

IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'copyTable')
SELECT * INTO copyTable FROM MyTable

次に、トリガーの開始時にソース テーブルとそのコピーを比較しています。

SELECT A.* FROM MyTable A, copyTable B WHERE
    A.id IN (SELECT [id] FROM INSERTED) AND
    A.id = B.id AND
    A.{0} <> B.{0}

{0} を必要な列に置き換えます。このコラムはまさにあなたが知っておくべきコラムであり、更新されているかどうかです。私の場合、動的に定義されていますが、必要なすべての列を静的にカウントできます。

出来上がり - 実際に変更された行だけを選択しました。

最後に、トリガーの最後に、copyTable を新しい値で更新することを忘れないでください。

UPDATE copyTable SET
    id = s.id,
    col1 = s.col1,
    ... all columns you'd like to control ...
FROM MyTable s WHERE
    s.id IN (SELECT [id] FROM INSERTED) AND
    copyTable.id = s.id

もっと良い解決策があるかもしれませんが、これもうまくいきます。

よろしく、

于 2010-07-12T23:56:46.093 に答える