組み合わせトリガーには、行前、行後、ステートメント前、ステートメント後の4種類のトリガーイベントのうち、1つから4つを含めることができます。または、INSTEAD OFトリガーイベントのみを含むこともできます。
概要
テーブルまたは編集可能なビューに作成された組み合わせトリガーは、複数の時点で発生することができます。組み合わせトリガーは各時点ごとにセグメントに分かれており、各時間帯には実行部と例外処理部(オプション)があります。これらすべての部分は共通のPL状態にアクセスできます。この共通状態はトリガーステートメントの開始時に確立され、トリガーステートメントの終了時に破棄されます。トリガーステートメントがエラーを引き起こした場合でも影響を受けません。
組み合わせトリガーの制限事項
組み合わせDMLトリガーには以下の制限があります:
OLD、NEW、PARENTは宣言部に現れることはできません。また、BEFORE STATEMENT部分やAFTER STATEMENT部分にも現れることはできません。NEWの値を変更できるのはBEFORE EACH ROW部分のみです。ある時間帯では、別の時間帯で発生した例外を処理することはできません。
時間帯内に
GOTOステートメントが含まれる場合、そのGOTOステートメントのターゲットは同一の時間帯内に存在している必要があります。
トリガーの作成
組み合わせトリガーの宣言部(オプション)では、時間点で区切られたすべてのセグメントで使用できる変数とサブプログラムを宣言できます。トリガーが発生すると、宣言部は任意の時間帯が実行される前に実行されます。変数とサブプログラムは、トリガーステートメントが作用する時間帯内に存在します。
編集不可なビューに作成された組み合わせトリガーは、実際の意味での組み合わせトリガーではありません。なぜなら、それには1つの時間帯しかないからです。編集不可なビューに単純な組み合わせトリガーを作成する構文は以下のとおりです:
CREATE TRIGGER FOR dml_event_clause ON view_name
[{ FOLLOWS | PRECEDES } other_trigger_name]
COMPOUND TRIGGER
INSTEAD OF EACH ROW IS BEGIN
sql_statement;
END INSTEAD OF EACH ROW;
テーブルまたは編集可能なビューに作成された組み合わせトリガーには、少なくとも1つの時間帯があります。トリガーに複数の時間帯がある場合、それらは任意の順序で配置できますが、時間点は重複してはなりません。時間帯が存在しない場合、その時間点では何の操作も発生しません。
組み合わせトリガーには主に以下の時間帯があります:
時間節点 |
時間帯 |
|---|---|
| トリガーステートメント実行前 | BEFORE STATEMENT |
| トリガーステートメント実行後 | AFTER STATEMENT |
| トリガーステートメントの影響を受ける各行の前 | BEFORE EACH ROW |
| トリガーステートメントの影響を受ける各行の後 | AFTER EACH ROW |
組み合わせトリガーには初期化部はありませんが、BEFORE STATEMENT では必要な初期化を行うことができます。これは他の時間帯よりも先に実行されるためです。
組み合わせトリガーに BEFORE STATEMENT 部分も AFTER STATEMENT 部分もなく、かつそのトリガーステートメントがいずれの行にも影響を与えない場合、トリガーは決して発生しません。
組み合わせトリガーを使用して、変更情報をテーブルのサブテーブルに記録します。例:
employeesとemp_salariesの2つのテーブルが存在すると仮定します。obclient [SYS]> CREATE TABLE employees ( employee_id NUMBER PRIMARY KEY, name VARCHAR2(50), salary NUMBER(8,2), department_id NUMBER);obclient [SYS]> CREATE TABLE emp_salaries ( emp_id NUMBER NOT NULL, change_date DATE NOT NULL, salary NUMBER(8,2) NOT NULL, FOREIGN KEY (emp_id) REFERENCES employees (employee_id) ON DELETE CASCADE);同時に、テーブル
employeesのデータは以下のとおりです。obclient [SYS]> SELECT * FROM employees;+-------------+------+--------+---------------+ | EMPLOYEE_ID | NAME | SALARY | DEPARTMENT_ID | +-------------+------+--------+---------------+ | 1001 | zs | 4400 | 50 | | 1002 | li | 4840 | 50 | | 1003 | wong | 5104 | 50 | | 1004 | xin | 5984 | 50 | | 1005 | mai | 5984 | 50 | | 1006 | cai | 5280 | 50 | | 1007 | cai | 7040 | 50 | | 1008 | cai | 7084 | 50 | | 1009 | deng | 6644 | 50 | | 1010 | yang | 6160 | 50 | | 1011 | qiu | 7000 | 51 | +-------------+------+--------+---------------+ 11 rows in setトリガー
maintain_emp_salariesを作成します。obclient [SYS]> delimiter /obclient [SYS]> CREATE OR REPLACE TRIGGER maintain_emp_salaries FOR UPDATE OF salary ON employees COMPOUND TRIGGER threshold CONSTANT SIMPLE_INTEGER := 7; TYPE salaries_t IS TABLE OF emp_salaries%ROWTYPE INDEX BY SIMPLE_INTEGER; sal salaries_t; idx SIMPLE_INTEGER := 0; PROCEDURE flush_proc IS n CONSTANT SIMPLE_INTEGER := sal.count(); BEGIN FORALL j IN 1..n INSERT INTO emp_salaries VALUES sal(j); sal.delete(); idx := 0; DBMS_OUTPUT.PUT_LINE('フラッシュ' || n || '行'); END flush_proc; -- AFTER EACH ROW セグメント: AFTER EACH ROW IS BEGIN idx := idx + 1; sal(idx).emp_id := :NEW.employee_id; sal(idx).change_date := SYSTIMESTAMP; sal(idx).salary := :NEW.salary; IF idx >= threshold THEN flush_proc(); END IF; END AFTER EACH ROW; -- AFTER STATEMENT時間帯: AFTER STATEMENT IS BEGIN flush_proc(); END AFTER STATEMENT; END maintain_emp_salaries; /obclient [SYS]> SET SERVEROUTPUT ON;部門
50の各従業員の給与を8%引き上げます。obclient [SYS]> UPDATE employees SET salary = salary * 1.08 WHERE department_id = 50 / Query OK, 10 rows affected Rows matched: 10 Changed: 10 Warnings: 0 7行をフラッシュ Flushed 7 rows 3行をフラッシュ Flushed 3 rows3秒待ってから、以下のコマンドを実行します:
obclient [SYS]> BEGIN DBMS_LOCK.SLEEP(3); END /部門
50の各従業員の給与を10%引き上げます。obclient [SYS]> UPDATE employees SET salary = salary * 1.1 WHERE department_id = 50 / Query OK, 10 rows affected Rows matched: 10 Changed: 10 Warnings: 0 7行をフラッシュ Flushed 7 rows 3行をフラッシュ Flushed 3 rowsemp_salariesテーブルの従業員テーブルの変更状況を確認します。obclient [SYS]> SELECT emp_id, count(*) num FROM emp_salaries GROUP BY emp_id /クエリ結果は次のとおりです:
+--------+------+ | EMP_ID | NUM | +--------+------+ | 1001 | 2 | | 1002 | 2 | | 1003 | 2 | | 1004 | 2 | | 1005 | 2 | | 1006 | 2 | | 1007 | 2 | | 1008 | 2 | | 1009 | 2 | | 1010 | 2 | +--------+------+ 10 rows in set