DMLトリガーを試す
トリガーをほぼ使ったことがないトリガー初心者なのですが、使う機会がでてきそうで調べていました。とりあえずDMLトリガーの、さらにAFTERトリガーにしぼって気になったところを試してみたので、少しメモとして残しておきます。
まずはテスト用のテーブルとトリガーを用意しました。
-- テーブルの定義 create table Temp( Id tinyint not null, Text nvarchar(5), constraint PK_Temp primary key(Id)); go -- トリガーの定義 create trigger TempTrigger on Temp after insert, update, delete as print N'trigger'; -- deletedテーブルで削除されたレコード、 -- insertedテーブルで挿入されたレコードを参照できる select N'deleted' as Type, * from deleted union all select N'inserted' as Type, * from inserted; -- UPDATE関数でカラムが更新されたかどうかを判断し、メッセージを表示 if update(Text) print N'column updated(Text)';
INSERT、UPDATE、DELETEのすべてに対してトリガーが実行されるように定義しています。また、トリガー内で使うことができる、insertedテーブル・deletedテーブルから影響を受けた行のコピーを参照できるので、それぞれSELECTしています。
UPDATE関数を使うと、指定したカラムでINSERTまたはUPDATEが行われたどうかを判断できます。
INSERT時は常にtrueが返るようです。
INSERT 動作では、列には明示的な値または暗黙的な (NULL) 値が挿入されるので、IF UPDATE は TRUE の値を返します。
DELETE時には常にfalseが返るようです。(というよりDELETEトリガーについての記述がないので、DELETE時には意味がないような気がします。)
UPDATE() は Transact-SQL の INSERT または UPDATE トリガーの内部のどこでも使用でき、そのトリガーが特定の動作を実行すべきかどうかをテストすることができます。
このトリガーを使っていくつか動きを確認してみました。
INSERTごとにトリガーが実行される
当然かもですが、INSERTを行うごとにトリガーも実行されます。次の例ではトリガーは2回実行されます。UPDATEやDELETEも同じです。insertedテーブルで挿入したレコードの内容を確認できます。
insert into Temp(Id, Text) values(1, N'a'); insert into Temp(Id, Text) values(2, N'b'); -- 実行結果 /* trigger Type Id Text -------- ---- ----- inserted 1 a column updated(Text) */ /* trigger Type Id Text -------- ---- ----- inserted 2 b column updated(Text) */
1つのINSERT文で複数のレコードを挿入する場合
次にように1つのINSERT文で複数レコードを挿入した場合は、トリガーの実行は1回です。insertedテーブルでは挿入した複数レコードを参照できます。
insert into Temp(Id, Text) values(3, N'c'), (4, N'd'); /* trigger Type Id Text -------- ---- ----- inserted 4 d inserted 3 c column updated(Text) */
INSERT文でTextカラムの値を設定しない場合
この場合もUPDATE関数はtrueを返します。NULL値で挿入されるということですね。
insert into Temp(Id) values(5); /* trigger Type Id Text -------- ---- ----- inserted 5 NULL column updated(Text) */
UPDATEトリガー
まずは普通にUPDATE。deletedテーブルで変更前、insertedテーブルで変更後のレコードを参照できます。UPDATE関数もtrueを返しています。
update Temp set Text = N'e' where Id = 5; /* trigger Type Id Text -------- ---- ----- deleted 5 NULL inserted 5 e column updated(Text) */
UPDATE文でTextカラムを更新しない場合
Textカラムを更新しないと、UPDATE関数はfalseを返します。
update Temp set Id = 6 where Id = 5; /* trigger Type Id Text -------- ---- ----- deleted 5 e inserted 6 e */
DELETEトリガー
deletedテーブルで削除したレコードを参照できます。
delete from Temp where Id = 1 or Id = 2; /* trigger Type Id Text -------- ---- ----- deleted 2 b deleted 1 a */
条件にマッチするデータがない場合
当然なのかもしれませんが、WHERE句の条件にマッチするデータがないときでもトリガーは実行されます。deletedテーブル、insertedテーブルは空です。この場合でもUPDATE関数はtrueを返すようです。
update Temp set Text = N'x' where Id = 1; -- Idが1のレコードは存在しない /* trigger Type Id Text -------- ---- ----- column updated(Text) */
DELETE文でも同じようにトリガーが実行されます。
delete from Temp where Id = 1; -- Idが1のレコードは存在しない /* trigger Type Id Text -------- ---- ----- */
まとまってないですし、考えていくと他にも気になるパターンは出てきてそうですが、とりあえずこの辺で・・・。