トリガーの制限
すべてのPL/SQLユニットに適用される制限に加えて(表C-1を参照)、トリガーには次の制限があります。
-
自律型トリガーのみがTCL文またはDDL文を実行できます。
自立型トリガーの詳細は、「自律型トリガー」を参照してください。
-
サブプログラムはトリガー本体のコンテキスト内で実行されるため、トリガーでは、トランザクション制御文を実行するサブプログラムを起動できません。
トリガーによって起動されるサブプログラムの詳細は、「トリガーによって起動されるサブプログラム」を参照してください。
-
トリガーでは、
SERIALLY_REUSABLE
パッケージにアクセスできません。SERIALLY_REUSABLE
パッケージの詳細は、「SERIALLY_REUSABLEパッケージ」を参照してください。
関連項目:
トリガーのサイズ制限
トリガーのサイズは、32K以下にしてください。
トリガーのロジックで60行をはるかに超えるPL/SQLソース・テキストが必要な場合は、そのソース・テキストの大部分をストアド・サブプログラムに組み込んで、トリガーからそのサブプログラムを起動してください。トリガーによって起動されるサブプログラムの詳細は、「トリガーによって起動されるサブプログラム」を参照してください。
トリガーのLONGおよびLONG RAWデータ型の制約
ノート:
Oracleは、既存アプリケーションとの下位互換性のためにのみ、LONG
およびLONG
RAW
データ型をサポートしています。
LONG
データ型からLOB
データ型に列を移行する方法の詳細は、Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイドを参照してください。
すべてのPL/SQLユニットに適用される制限に加えて(「LONGおよびLONG RAW変数」を参照)、トリガーには次の制限があります。
-
トリガーでは、
LONG
またはLONG
RAW
データ型の変数を宣言できません。 -
トリガー内のSQL文では、列データを
CHAR
またはVARCHAR2
データ型に変換できる場合にのみ、LONG
またはLONG
RAW
列を参照できます。 -
トリガーでは、LONGまたは
LONG RAW
列で相関名の
NEW
またはPARENT
を使用できません。
変更表の制限
ノート:
このトピックの内容は、行レベルの単純なDMLトリガーにのみ適用されます。
変更表とは、DML文で(状況によってはDELETE
CASCADE
制約の影響によって)現在変更されている表です。(INSTEAD
OF
トリガーによって変更中のビューは、変更ビューとはみなされません。)
変更表の制限のため、トリガーは、トリガーを起動する文が変更中の表を問い合せたり、変更することはできません。行レベルのトリガーで変更表が検出されると、ORA-04091が発生し、トリガーおよびトリガーを起動する文の影響がロールバックされ、トリガーを起動する文を発行したユーザーまたはアプリケーションに制御が戻されます(例10-26を参照)。
注意:
Oracle Databaseでは、分散データベースの異なるノード上に存在する表の間の宣言参照制約はサポートされないため、リモート・ノードにアクセスするトリガーに関する変更表の制限は適用されません。
同様に、データベースでは、ループバック・データベース・リンクで接続されている同一データベース内の表に関する変更表の制限も適用されません。ループバック・データベース・リンクによって、リンクを含むデータベースに戻るOracle Netパスが定義され、ローカル表がリモートで表示されます。
トリガーを使用して変更表を更新する必要がある場合、次のいずれかの方法で変更表エラーを回避できます。
-
複合DMLトリガーを使用します(「複合DMLトリガーを使用した変更表エラーの回避」を参照)。
-
一時表を使用します。
たとえば、変更表を更新する1つの
AFTER
行単位トリガーを使用するかわりに、一時表を更新するAFTER
行単位トリガーおよび一時表からの値を使用して変更表を更新するAFTER
文トリガーの2つのトリガーを使用します。
変更表の制限の緩和
Oracle Database 8gリリース1以上では、親表に対して削除を行うと、BEFORE
およびAFTER
トリガーが1回起動されます。したがって、親表および子表の問合せおよび変更を実行する行レベルと文レベルのトリガーを作成できます。制約が自己参照的でない場合、これによって、ほとんどの外部キー制約アクションはそれらのAFTER行トリガーを介して実装されます。更新カスケード、更新セットNULL、更新セット・デフォルト、削除セット・デフォルト、欠落した親の挿入および子のカウントの保持をすべて簡単に実装できます(「参照整合性を保証するトリガー」を参照)。
ただし、カスケードでは、複数行の外部キーを更新する場合に注意が必要です。外部キー制約によって、AFTER行トリガーが起動されるまでいずれの一致する外部キー行もロックされないことが保証されているため、トリガーは、別のトランザクションによってコミットされていない変更済の行を見逃すことはありません。
例10-27では、トリガーを起動する文によってp
は正常に更新されますが、トリガーがf
を更新するときに問題が発生します。まず、トリガーを起動する文はp
の値(1)から(2)への変更を行い、トリガーはf
に値(2)の行を2つ残したままf
の値(1)から(2)への更新を行います。次に、トリガーを起動する文はp
の値(2)から(3)への更新を行い、トリガーはf
の2つの行の値を両方とも(2)から(3)へ更新します。最後に、この文はp
の値(3)から(4)への更新を行い、トリガーはfの3つすべての行を(3)から(4)へ更新します。p
とf
のデータ項目間の関係は失われます。
この問題を回避するには、主キーを変更するp
の複数行更新を禁止して既存の主キー値を再利用するか、または外部キー値の更新を追跡して行が2回更新されないようにトリガーを変更します。
例10-26 トリガーによる変更表エラー
-- Create log table DROP TABLE log; CREATE TABLE log ( emp_id NUMBER(6), l_name VARCHAR2(25), f_name VARCHAR2(20) ); -- Create trigger that updates log and then reads employees CREATE OR REPLACE TRIGGER log_deletions AFTER DELETE ON employees FOR EACH ROW DECLARE n INTEGER; BEGIN INSERT INTO log VALUES ( :OLD.employee_id, :OLD.last_name, :OLD.first_name ); SELECT COUNT(*) INTO n FROM employees; DBMS_OUTPUT.PUT_LINE('There are now ' || n || ' employees.'); END; / -- Issue triggering statement: DELETE FROM employees WHERE employee_id = 197;
結果:
DELETE FROM employees WHERE employee_id = 197
*
ERROR at line 1:
ORA-04091: table HR.EMPLOYEES is mutating, trigger/function might not see it
ORA-06512: at "HR.LOG_DELETIONS", line 10
ORA-04088: error during execution of trigger 'HR.LOG_DELETIONS'
トリガーの影響がロールバックされていることの確認:
SELECT count(*) FROM log;
結果:
COUNT(*) ---------- 0 1 row selected.
トリガーを起動する文の影響がロールバックされていることの確認:
SELECT employee_id, last_name FROM employees WHERE employee_id = 197;
結果:
EMPLOYEE_ID LAST_NAME ----------- ------------------------- 197 Feeney 1 row selected.
例10-27 更新カスケード
DROP TABLE p; CREATE TABLE p (p1 NUMBER CONSTRAINT pk_p_p1 PRIMARY KEY); INSERT INTO p VALUES (1); INSERT INTO p VALUES (2); INSERT INTO p VALUES (3); DROP TABLE f; CREATE TABLE f (f1 NUMBER CONSTRAINT fk_f_f1 REFERENCES p); INSERT INTO f VALUES (1); INSERT INTO f VALUES (2); INSERT INTO f VALUES (3); CREATE TRIGGER pt AFTER UPDATE ON p FOR EACH ROW BEGIN UPDATE f SET f1 = :NEW.p1 WHERE f1 = :OLD.p1; END; /
問合せ:
SELECT * FROM p ORDER BY p1;
結果:
P1 ---------- 1 2 3
問合せ:
SELECT * FROM f ORDER BY f1;
結果:
F1 ---------- 1 2 3
トリガーを起動する文の発行:
UPDATE p SET p1 = p1+1;
問合せ:
SELECT * FROM p ORDER BY p1;
結果:
P1 ---------- 2 3 4
問合せ:
SELECT * FROM f ORDER BY f1;
結果:
F1 ---------- 4 4 4