私はちょうどこの問題(というか、似たような問題)を抱えていたので、復活しました...
私の最終的なアプローチは、トリガーを壊すという理由だけで PK フィールドへの更新を単純に禁止することでした。ありがたいことに、主キー列の更新をサポートするビジネス ケースがなかったので (とにかく、これらはサロゲート ID でした)、それでうまくいくことができました。
SQL Server は、UPDATE
トリガー内で使用するために、このエッジ ケースをチェックする関数を提供します。
CREATE TRIGGER your_trigger
ON your_table
INSTEAD OF UPDATE
AS BEGIN
IF UPDATE(pk1) BEGIN
ROLLBACK
DECLARE @proc SYSNAME, @table SYSNAME
SELECT TOP 1
@proc = OBJECT_NAME(@@PROCID)
,@table = OBJECT_NAME(parent_id)
FROM sys.triggers
WHERE object_id = @@PROCID
RAISERROR ('Trigger %s prevents UPDATE of table %s due to locked primary key', 16, -1, @proc, @table) WITH NOWAIT
END
ELSE UPDATE t SET
col1 = i.col1
,col2 = i.col2
,col3 = i.col3
FROM your_table t
INNER JOIN inserted i ON t.pk1 = i.pk1
END
GO
(上記はテストされておらず、おそらくXACT_STATE
orに関するあらゆる種類の問題が含まれていることに注意してくださいTRIGGER_NESTLEVEL
-- 原理を示すためだけに存在します)
ただし、少し面倒なので、開発中にテーブルへの変更を処理するために、コード生成を検討します (おそらく、CREATE/ALTER テーブルの DDL トリガーによって行われることもあります)。
複合主キーがある場合は、関数を使用するIF UPDATE(pk1) OR UPDATE(pk2)...
か、COLUMNS_UPDATED
関数でビット単位の作業を行うことができます。これにより、列の序数に基づいてビットマスクが得られます (ただし、ここでは説明しません。MSDN/BOL を参照してください)。
他の (より単純な) オプションは toですが、 (そしておそらく)DENY UPDATE ON your_table(pk) TO public
のメンバーはこれを尊重しないことに注意してください。sysadmins
dbo