14. トリガー (SQL 非標準)
14.1. トリガーとは
トリガーは、表に対して何らかの変更処理が加えられたときに、その変更処理をきっかけとして自動的に実行される特殊なストアドプロシージャのことです。表に対するなんらかの変更処理とは、INSERT 文、UPDATE 文及び DELETE 文といったデータ操作文を実行することです。
トリガーを定義するときには、その対象となるテーブル、トリガーが起動するきっかけとなる表に対する変更処理、トリガーの処理内容、トリガーの起動するタイミングなどを指定します。トリガーは指定したテーブルを監視し、指定した変更処理がテーブルに対して行われると、指定したタイミングで指定した処理を実行します。
トリガーはアプリケーションから呼び出されるものではなく、アプリケーションには全く依存しないものです。ですから、あるアプリケーションにより、テーブルのデータが変更されても、データの整合性を保つようにトリガーを定義しておけば、他のアプリケーションによりデータが変更されてもデータの整合性は確保されます。例えば、受注表にデータを追加すると同時に、在庫表のデータを更新するアプリケーション A を作成したとします。アプリケーション A を日常的に使用しているときに、何らかの理由で受注表にデータを追加だけを行うアプリケーション B を実行してしまうと、データの整合性がなくなることになります。
このような場合、受注表にデータが追加されたときに、在庫表のデータを更新するようにトリガーを定義しておけば、どのアプリケーションでデータを追加したとしても、在庫表のデータの整合性を確保することができます。
また、さまざまなアプリケーションで共通に実行する処理をトリガーに定義しておけば、アプリケーションを簡略化することができます。アプリケーション側では、テーブルに対するデータ操作文だけを実行するようにしておき、後の処理はトリガーに任せてしまうことにより、保守が容易になります。
このように、トリガーを利用することにより、いくつかのメリットがありますが、デメリットが生じることもあります。トリガーはテーブルにデータ操作文が実行されるたびに実行されるものです。ですから、データ操作を頻繁に行うアプリケーションでトリガーを多用するとパフォーマンスが低下することがあります。また、アプリケーション自体はトリガーによってどのような処理が行われるのかを知ることができません。そのため、トリガーを多用すると、アプリケーションによる処理とトリガーによる処理の関係がわかりにくくなり、全体としての処理内容を把握しにくくなります。その結果保守性が低下することがあります。
14.2. トリガーの基本構文
トリガーについても、ストアドプロシージャと同様に、SQL92 では定義されていません。ここでは、ORACLE と PostgreSQL について説明します。
CREATE TRIGGER 文を用いてトリガーを定義します。ORACLE の基本構文を次に示します。
<<ORACLE>>CREATE [ OR REPLACE ] TRIGGER トリガー名 { BEFORE | AFTER | INSTEAD OF } { INSERT | UPDATE [OF 列名,...] | DELETE } [OR {INSERT | UPDATE [OF 列名,...] | DELETE }] [... ] ON テーブル名 [ FOR EACH ROW ] [ WHEN 条件式 ] BEGIN 処理内容 END ;
OR REPLACE 句を指定すると、同じ名前のトリガーが既に存在するときに上書きします。
{ BEFORE | AFTER | INSTEAD OF }は、トリガーがいつ起動するのかを指定するキーワードです。
- BEFORE
- テーブルに対してデータ操作文が発行されたときに、そのデータ操作文が実行される前にトリガーを起動します。
- AFTER
- テーブルに対してデータ操作文が発行されたときに、そのデータ操作文が実行された後にトリガーを起動します。
- INSTEAD OF
- テーブルに対してデータ操作文が発行されたときに、そのデータ操作文は実行されず、トリガーだけを起動します。
{ INSERT | UPDATE [OF 列名,...] | DELETE } は、この 3つのデータ操作文のうち、どれが発行されたときにトリガーが起動するのかを指定します。UPDATE については、OF 句に続けて列を指定すれば、指定した列のいずれかが更新される場合にだけトリガーを起動します。OR 句を用いて複数のデータ操作文を指定することができます。
ON 句の後ろには、どのテーブルに対するデータ操作文が発行された時にトリガーを起動するのかを指定します。
FOR EACH ROW を指定すると、複数の行に対するデータ操作文が発行されるとき、各行ごとにトリガーが起動します。これを指定しない場合は、複数の行に対するデータ操作文が発行されても、トリガーは一度だけしか起動されません。
WHEN 句は、ここに指定された条件を満たす場合にのみ、トリガーを起動するように設定するものです。ここで条件を指定すると、例えば、追加された行の特定の列の値が条件を満たす場合にのみ、トリガーを起動するように設定することができます。
処理内容には、トリガーが起動したときにどのような処理が行われるのかを記述します。
続いて PostgreSQL の基本構文について説明します。
<<PostgreSQL>>CREATE TRIGGER トリガー名 { BEFORE | AFTER } { INSERT | UPDATE [OF 列名,...] | DELETE } [ OR { INSERT | UPDATE [OF 列名,...] | DELETE}] [ ... ] ON テーブル名 FOR EACH { ROW | STATEMENT } [ WHEN 条件式 ] EXECUTE PROCEDURE 関数名(引数) ;
ほぼ、ORACLE と同じですので、ここでは ORACLE と異なる部分についてのみ説明します。{ BEFORE | AFTER } では、トリガーがいつ起動するのかを指定しますが、PostgreSQL では BEFORE と AFTER のみサポートしています。
PostgreSQL では、複数の行に対するデータ操作文が発行されるときに、行ごとに起動するのか、一度だけ起動するのかを指定するために、どちらの場合も明示的に指定します。一行ごとに起動するときは FOR EACH ROW、一度だけしか起動しない場合はFOR EACH STATEMENTとします。
最後に、トリガーの処理内容についてですが、PostgreSQL の場合は予め定義しておいた関数名を EXECUTE PROCEDURE に続けて記述します。引数が必要な場合は引数も記述します。このとき利用できる関数は、PL/pgSQL 関数か C 関数でなければなりません。また、関数の返り値は OPAQUE 型 (不明なデータ型) でなければなりません。
定義したトリガーは、いつでも起動される状態になっています。しかし状況によっては、一時的にトリガーを無効にしたい場合もあります。このような場面に備えて ORACLE では、トリガーの有効 / 無効を切り替えることができる SQL 文が用意されています。基本構文は次のとおりです。
<<ORACLE>>ALTER TRIGGER トリガー名 { ENABLE | DISABLE | COMPILE } ;
ALTER TRIGGER 文でトリガーの有効、無効を切り替えます。ENABLE を指定するとトリガーが有効になり、テーブルにデータ操作文が発行されるとトリガーが起動します。DISABLE を指定するとトリガーは無効になります。トリガーは起動しなくなります。COMPILE を指定すると、トリガーが参照しているテーブルが変更された場合などに、トリガーをコンパイルし直します。
定義したトリガーを削除するには次の基本構文を使用します。
<<ORACLE>>DROP TRIGGER トリガー名 ;<<PostgreSQL>>
DROP TRIGGER トリガー名 ON テーブル名 ;
ORACLE ではトリガー名を指定するだけで削除されますが、PostgreSQL ではトリガー名とテーブル名を指定してトリガーを削除します。