トリガーの制限

すべてのPL/SQLユニットに適用される制限に加えて(表C-1を参照)、トリガーには次の制限があります。

トリガーのサイズ制限

トリガーのサイズは、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)へ更新します。pfのデータ項目間の関係は失われます。

この問題を回避するには、主キーを変更する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