1つの組み合わせトリガーには、行前、行後、ステートメント前、ステートメント後の4種類のトリガーイベントのうち1つから4つまでを含めることができます。または、INSTEAD OFトリガーイベントのみを含むこともできます。
概要
テーブルまたは編集可能なビュー上に作成された組み合わせトリガーは、複数の時間点でトリガーを発火させることができます。組み合わせトリガーは各時間点ごとにセグメントに分割され、各時間帯には独自の実行部と例外処理部(オプション)があります。これらすべての部分は共通のPL状態にアクセスできます。共通状態はトリガー文の開始時に確立され、トリガー文の完了時に破棄されます。トリガー文がエラーを引き起こした場合でも影響を受けません。
組み合わせトリガーの使用制限
組み合わせDMLトリガーには以下の制限があります:
OLD、NEW、およびPARENTは宣言部に現れることはできず、BEFORE STATEMENT部またはAFTER STATEMENT部にも現れることはできません。NEWの値を変更できるのはBEFORE EACH ROW部のみです。ある時間帯では、別の時間帯で発生した例外を処理することはできません。
ある時間帯に
GOTO文が含まれている場合、そのGOTO文のターゲットは同一時間帯内でなければなりません。
トリガーの作成
複合トリガーの宣言部(オプション)では、時間点で区切られたすべてのセグメントで使用可能な変数とサブルーチンを宣言できます。トリガーが発火すると、宣言部は任意の時間帯が実行される前に実行されます。変数とサブルーチンは、トリガー文が適用される時間帯内に存在します。
編集不可能なビュー上に作成される複合トリガーは、実際の意味での複合トリガーではありません。これは、単一の時間帯しか持たないためです。編集不可能なビュー上に単純な複合トリガーを作成する構文は次のとおりです:
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 部分もなく、かつそのトリガー文がどの行にも影響を与えない場合、トリガーは決して発火しません。
複合トリガーを使用して、変更情報をテーブルのサブテーブルに記録します。例:
2つのテーブル
employeesとemp_salariesが存在すると仮定します。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('Refreshed' || n || ' rows'); 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 Refreshed 7 rows Flushed 7 rows Refreshed 3 rows 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 Refreshed 7 rows Flushed 7 rows Refreshed 3 rows 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