CREATE TRIGGER — 新しいトリガを定義する
CREATE [ CONSTRAINT ] TRIGGERname
{ BEFORE | AFTER | INSTEAD OF } {event
[ OR ... ] } ONtable_name
[ FROMreferenced_table_name
] [ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ] [ FOR [ EACH ] { ROW | STATEMENT } ] [ WHEN (condition
) ] EXECUTE PROCEDUREfunction_name
(arguments
) ここでevent
は以下のいずれかを取ることができます。 INSERT UPDATE [ OFcolumn_name
[, ... ] ] DELETE TRUNCATE
CREATE TRIGGER
は新しいトリガを作成します。
作成したトリガは指定したテーブル、ビューまたは外部テーブルと関連付けられ、特定のイベントが発生した時に指定した関数function_name
を実行します。
トリガでは、起動のタイミングとして、行への操作が開始される前(制約条件のチェックとINSERT
、UPDATE
またはDELETE
が行われる前)、操作が完了した後(制約条件がチェックされ、INSERT
、UPDATE
またはDELETE
が完了した後)、操作の代わり(ビューにおける挿入、更新、削除の場合)のいずれかを指定することができます。
イベントの前または代わりにトリガが起動する場合、そのトリガは対象行に対する操作を省略したり、(INSERT
とUPDATE
の操作時のみ)挿入する行を変更したりすることができます。
イベントの後にトリガが起動する場合、他のトリガの影響を含む全ての変更が、トリガに対して「可視」状態となります。
FOR EACH ROW
付きのトリガは、その操作によって変更される行ごとに1回ずつ呼び出されます。
例えば、10行に影響を与えるDELETE
操作は、対象リレーション上のすべてのON DELETE
トリガを、削除される各行について1回ずつ、個別に10回呼び出すことになります。
反対に、FOR EACH STATEMENT
付きのトリガは、その操作によって何行変更されたかにかかわらず、任意の操作ごとに1回のみ実行されます
(変更対象が0行となる操作でも、適用できるすべてのFOR EACH STATEMENT
トリガが実行されます)。
ON CONFLICT DO UPDATE
句を含むINSERT
では、INSERT
とUPDATE
の両方の文レベルトリガが実行されることに注意してください。
トリガイベントのINSTEAD OF
として発行されるように指定されたトリガはFOR EACH ROW
印を付けなければなりません。
またビュー上にのみ定義することができます。
ビューに対するBEFORE
およびAFTER
トリガはFOR EACH STATEMENT
印を付けなければなりません。
さらに、FOR EACH STATEMENT
のみですが、トリガをTRUNCATE
に対して発行するように定義することができます。
以下の表にどの種類のトリガがテーブル、ビュー、外部テーブルに対して使用できるかをまとめます。
いつ | イベント | 行レベル | 文レベル |
---|---|---|---|
BEFORE | INSERT /UPDATE /DELETE | テーブル、および外部テーブル | テーブル、ビューおよび外部テーブル |
TRUNCATE | — | テーブル | |
AFTER | INSERT /UPDATE /DELETE | テーブルおよび外部テーブル | テーブル、ビューおよび外部テーブル |
TRUNCATE | — | テーブル | |
INSTEAD OF | INSERT /UPDATE /DELETE | ビュー | — |
TRUNCATE | — | — |
またトリガ定義では、論理値のWHEN
条件を指定することができ、これによってトリガを発行すべきかどうかが判定されます。
行レベルのトリガでは、WHEN
条件は行の列の古い値、新しい値、またはその両方で検証することができます。
文レベルのトリガでもWHEN
条件を持たせることができますが、条件としてテーブル内のどの値も参照することができませんので、この機能はあまり有用ではありません
同一イベントに同じ種類の複数のトリガが定義された場合、名前のアルファベット順で実行されます。
CONSTRAINT
オプションが指定された場合、このコマンドは制約トリガを作成します。
これは、SET CONSTRAINTSを使用してトリガを発行するタイミングを調整することができるという点を除き、通常のトリガと同じです。
制約トリガはテーブルのAFTER ROW
トリガでなければなりません。
トリガイベントを引き起こした文の最後、またはそれを含むトランザクションの最後のいずれかで発行することができます。
後者の場合、遅延と呼ばれます。
SET CONSTRAINTS
を使用することで、強制的に待機中の遅延トリガの発行を即座に行わせることができます。
制約トリガは、実装する制約に違反した時に例外を発生するものと想定されています。
SELECT
はまったく行を変更しないため、SELECT
トリガを作成することはできません。
この場合は、ルールやビューの方が適しています。
トリガに関するより詳細については、36章トリガを参照してください。
name
新しいトリガに付与する名前です。
同じテーブルの他のトリガと異なる名前にする必要があります。
名前をスキーマ修飾することはできません。
トリガはそのテーブルのスキーマを引き継ぎます。
制約トリガの場合、この名前がSET CONSTRAINTS
を使用してトリガの動作を変更する時に使用されます。
BEFORE
AFTER
INSTEAD OF
関数の呼び出しをイベントの前に行うか後に行うか、それとも代替として行うかを決定します。
制約トリガではAFTER
としてしか指定することができません。
event
INSERT
、UPDATE
、DELETE
、TRUNCATE
のいずれかが入ります。
このパラメータは、トリガを起動するイベントを指定します。
OR
を使用して、複数のイベントを指定することができます。
UPDATE
イベントでは、以下の構文を使用して列リストを指定することができます。
UPDATE OFcolumn_name1
[,column_name2
... ]
このトリガはUPDATE
コマンドの対象として列挙された列のいずれか少なくとも1つの列が指定された場合に発行されます。
INSTEAD OF UPDATE
イベントは列リストをサポートしません。
table_name
トリガを作成するテーブル、ビューまたは外部テーブルの名前です(スキーマ修飾名も可)。
referenced_table_name
制約で参照される他のテーブルの名前(スキーマ修飾可)です。 このオプションは外部キー制約で使用されるものであり、一般利用を推奨しません。 これは制約トリガでのみ指定することができます。
DEFERRABLE
NOT DEFERRABLE
INITIALLY IMMEDIATE
INITIALLY DEFERRED
トリガのデフォルトのタイミングです。 これらの制約オプションについてはCREATE TABLE文書を参照してください。 これは制約トリガでのみ指定することができます。
FOR EACH ROW
FOR EACH STATEMENT
このパラメータは、トリガプロシージャを、トリガイベントによって影響を受ける行ごとに1回起動するか、SQL文ごとに1回のみ起動するかを指定します。
どちらも指定されない場合は、FOR EACH STATEMENT
がデフォルトです。
制約トリガはFOR EACH ROW
のみ指定することができます。
condition
トリガ関数を実際に実行するか否かを決定する論理式です。
WHEN
が指定された場合、condition
がtrue
を返す場合のみ関数が呼び出されます。
FOR EACH ROW
トリガでは、WHEN
条件で、それぞれOLD.
、column_name
NEW.
と記述することで、古い行の値、新しい行の値、またはその両方の列を参照することができます。
当然ながらcolumn_name
INSERT
トリガではOLD
を参照することはできませんし、DELETE
トリガではNEW
を参照することはできません。
INSTEAD OF
トリガはWHEN
条件をサポートしません。
現時点ではWHEN
条件に副問い合わせを含めることはできません。
制約トリガでは、WHEN
条件の評価は遅延されず、行の更新操作が行われた直後に発生することに注意してください。
この条件が真と評価されなかった場合、トリガは遅延実行用のキューに入りません。
function_name
ユーザが提供する関数です。この関数は、引数を取らずtrigger
型を返すよう定義されます。トリガが起動した時に実行されます。
arguments
トリガ実行時に関数に渡される引数をカンマで区切ったリストで、省略可能です。 引数として指定するのは、リテラル文字列定数です。 単純な名前および数値定数を記述できますが、全て文字列に変換されます。 関数内でこれらの引数にアクセスする方法について調べるためには、トリガ関数を実装した言語の説明を参照してください。 通常の関数引数とは異なる場合があります。
テーブルにトリガを作成するには、ユーザがそのテーブルに対しTRIGGER
権限を持っている必要があります。
またユーザはトリガ関数に対しEXECUTE
権限を持たなければなりません。
トリガを削除するためにはDROP TRIGGERを使用してください。
列指定のトリガ(UPDATE OF
構文で定義されたトリガ)は、列挙された列のいずれかがcolumn_name
UPDATE
コマンドのSET
リスト内に対象として指定された場合に発行されます。
BEFORE UPDATE
トリガにより行の内容になされた変更は考慮されないため、トリガが発行されない場合であっても、列の値が変更されることはあります。
反対に、UPDATE ... SET x = x ...
のようなコマンドは、列の値が変更されませんが、x
列に対するトリガが発行されます。
BEFORE
トリガにおいてWHEN
条件は関数が実行される、またはされそうな直前に評価されます。
このためWHEN
の使用はトリガ関数の先頭で同一の条件を試験することと実質的に違いはありません。
この条件で確認できるNEW
行が現在の値であり、それまでのトリガで変更されている可能性があることに、特に注意して下さい。
またBEFORE
トリガのWHEN
条件では、NEW
行のシステム列(oid
など)はまだ設定されていないので、検査することができません。
AFTER
トリガにおいて、WHEN
条件は行の更新を行った直後に評価され、文の最後でトリガを発行するためにイベントを保持すべきかどうかを決定します。
このためAFTER
トリガのWHEN
条件は真を返さない場合、イベントを保持する必要もありませんし、文の最後の行を再度取り出す必要もありません。
これにより、トリガをわずかな行のみに対して発行する必要がある場合、多くの行を変更する文を非常に高速にすることができます。
PostgreSQL 7.3より前のバージョンでは、トリガ関数の戻り値の型を、trigger
型ではなくプレースホルダであるopaque
型として宣言する必要がありました。
古いダンプファイルのロードをサポートするため、CREATE TRIGGER
ではopaque
型を返すよう宣言された関数を受け入れます。
しかし、注意を促すメッセージを表示し、宣言された関数の戻り値型をtrigger
に変換します。
テーブルaccounts
の行が更新される直前に関数check_account_update
を実行します。
CREATE TRIGGER check_update BEFORE UPDATE ON accounts FOR EACH ROW EXECUTE PROCEDURE check_account_update();
上と同じです。
しかし、列balance
がUPDATE
コマンドの対象として指定された場合のみ実行されます。
CREATE TRIGGER check_update BEFORE UPDATE OF balance ON accounts FOR EACH ROW EXECUTE PROCEDURE check_account_update();
以下の構文では、列balance
が実際に変更された場合のみ関数が実行されます。
CREATE TRIGGER check_update BEFORE UPDATE ON accounts FOR EACH ROW WHEN (OLD.balance IS DISTINCT FROM NEW.balance) EXECUTE PROCEDURE check_account_update();
何か変更された場合のみにaccounts
の更新のログを取る関数を呼び出します。
CREATE TRIGGER log_update AFTER UPDATE ON accounts FOR EACH ROW WHEN (OLD.* IS DISTINCT FROM NEW.*) EXECUTE PROCEDURE log_account_update();
ビューの背後にあるテーブルに行を挿入するために、各行に対して関数view_insert_row
を実行します。
CREATE TRIGGER view_insert INSTEAD OF INSERT ON my_view FOR EACH ROW EXECUTE PROCEDURE view_insert_row();
36.4. 完全なトリガの例には、C言語で作成されたトリガ関数の完全な例があります。
PostgreSQLにおけるCREATE TRIGGER
文は標準SQLのサブセットを実装したものです
現在は、PostgreSQLには、次の機能がありません。
SQLでは、「old」や「new」、トリガによって起動する動作の定義が使用するテーブルに、別名を定義することができます。
(例えば、CREATE TRIGGER ... ON tablename REFERENCING OLD ROW AS somename NEW ROW AS othername ...
)。
PostgreSQLでは、複数のユーザ定義言語でトリガプロシージャを作成できるので、データへのアクセスは言語固有の方法で扱われます。
PostgreSQLでは、文レベルのトリガにおいて古いテーブルと新しいテーブル、つまり、古い行のすべて、新しい行のすべてまたはその両方を持つテーブルを参照することができません。
これは標準SQLではOLD TABLE
およびNEW TABLE
句により参照されます。
PostgreSQLでは、トリガ動作として、ユーザ定義関数の実行しか認めていません。
標準では、多数の他のSQLコマンドを実行させることができます。
例えば、トリガ動作としてCREATE TABLE
を実行させることも可能です。
この制限を回避する方法は簡単です。必要なコマンドを実行するユーザ定義関数を作成すればよいのです。
SQLでは、複数のトリガは、作成時刻順に起動すべきであると規定しています。 PostgreSQLでは名前順です。この方が便利だと考えられるからです。
SQLでは、数珠繋ぎの削除に対するBEFORE DELETE
は、数珠繋ぎのDELETE
が完了した後に発行するものと規定しています。
PostgreSQLでは、BEFORE DELETE
は常に削除操作よりも前に、それも起点となる削除よりも前に行われます。
この方がより一貫性があると考えられいます。
また、参照整合性に関する動作により引き起こされる更新を実行している間に、BEFORE
トリガが行を更新し、更新を妨げるような場合の動作も標準に従わないものがあります。
これは、制約違反となるかもしれませんし、参照整合性制約に合わないデータを格納してしまうかもしれません。
OR
を使用して単一トリガに複数の動作を指定する機能は、標準SQLに対するPostgreSQLの拡張です。
TRUNCATE
でのトリガ発行機能、および、ビューに対する文レベルのトリガの定義機能は標準SQLに対するPostgreSQLの拡張です。
CREATE CONSTRAINT TRIGGER
は標準SQLに対するPostgreSQLの拡張です。