アクションの前にFORトリガーが実行されないのはなぜですか?
-
03-07-2019 - |
質問
IsDeletedのフラグが設定されていない2つの名前の挿入を回避するために、テーブルにトリガーを書き込もうとしています。ただし、選択の最初の部分には挿入された部分が含まれるため、条件は常に真になります。 FORキーワードを使用すると、トリガーがINSERTIONの前に実行されますが、この場合、挿入された行は既にテーブルにあります。私は間違っているのですか、これがすべてのFORトリガーの仕組みですか?
ALTER TRIGGER TriggerName
ON MyTable
FOR INSERT, UPDATE
AS
BEGIN
If exist (select [Name] From MyTable WHERE IsDeleted = 0 AND [Name] in (SELECT [Name] FROM INSERTED)
BEGIN
RAISERROR ('ERROR Description', 16, 1);
Rollback;
END
END
解決
データが変更された後、FORが実行されます。INSTEADOFはあなたが望んでいることだと思います。
編集:他の人が述べたように、INSTEAD OFは変更するデータの代わりに実行されるため、無効な場合は挿入を停止するのではなく、有効な場合はデータを挿入する必要があります。
トリガーのタイプのより詳細な説明については、この質問をお読みください。
他のヒント
FORはAFTERと同じです。 「シミュレート」したい場合BEFOREトリガー、INSTEAD OFを使用、注意、適切なBEFOREトリガーで期待するものとは正確に一致しません。つまり、必要なINSTEADアクションを提供できない場合、挿入/更新されたデータは失われる/無視される可能性があります。
MSSQLにはBEFOREトリガーがありません。
SQL Serverの場合、FORはそれをトリガーしたSQLの後に実行されます。
から: http://msdn.microsoft.com/en-us/library/ms189799。 aspx
FOR |後
AFTER は、DMLトリガーを指定します すべての操作が行われたときにのみ起動されます トリガーSQLで指定 ステートメントは正常に実行されました。 すべての参照カスケードアクションと 制約チェックも成功する必要があります このトリガーが起動する前。
FORがAFTER がデフォルトです 指定されたキーワードのみ。
AFTER トリガー ビューで定義することはできません。
最近、実際に同様の問題に遭遇し、それを処理するためのクールな方法を見つけました。 1つのIDに対して複数の行を持つことができるテーブルがありましたが、プライマリとしてマークできるのはそのうちの1つだけです。
SQL Server 2008では、部分ユニークインデックスを次のように作成できます。
create unique index IX on MyTable(name) where isDeleted = 0;
ただし、SQL Server 2005でもう少し作業を行うことで実現できます。トリックは、削除されていない行のみを表示するビューを作成し、その上に一意のクラスター化インデックスを作成することです。
create view MyTableNotDeleted_vw
with schema_binding /* Must be schema bound to create an indexed view */
as
select name
from dbo.MyTable /* Have to use dbo. for schema bound views */
where isDeleted = 0;
GO
create unique clustered index IX on MyTableNotDeleted_vw ( name );
これは、まだ削除されていない行にのみ影響する一意の制約を効果的に作成し、おそらくカスタムトリガーよりも優れたパフォーマンスを発揮します!