組み合わせDMLトリガーは、テーブルまたは編集可能なビューに作成でき、複数の時点でのトリガーをサポートします。組み合わせトリガーは各時間点ごとにセクションに分かれており、各時間帯には独立した実行部と例外処理部(オプション)が含まれます。
機能の適用範囲
この内容はOceanBaseデータベースEnterprise Editionにのみ適用されます。OceanBaseデータベースCommunity EditionはMySQLモードのみを提供します。
組み合わせDMLトリガーの構文
最もシンプルな組み合わせDMLトリガーの構文は次のとおりです:
CREATE trigger_name FOR dml_event_clause ON view_name
COMPOUND TRIGGER
INSTEAD OF EACH ROW IS BEGIN
sql_statement;
END INSTEAD OF EACH ROW;
組み合わせDMLトリガーの宣言部(オプション)は、変数とサブプログラムを定義するために使用されます。トリガーが発生すると、まず宣言部が実行され、そこで定義された変数とサブプログラムは、トリガー文が適用される期間中存続します。
組み合わせDMLトリガーには少なくとも1つの時間区間が含まれます(下表参照)。組み合わせDMLトリガー内の複数の時間区間は任意の順序で配置できますが、時刻は重複してはなりません。
タイミングポイント |
期間 |
|---|---|
| トリガーステートメントの実行前 | BEFORE STATEMENT |
| トリガーステートメントの実行後 | AFTER STATEMENT |
| トリガーステートメントの影響を受ける各行の前 | BEFORE EACH ROW |
| トリガーステートメントの影響を受ける各行の後 | AFTER EACH ROW |
組み合わせDMLトリガーには初期化部が含まれません。BEFORE STATEMENT は他の時間区間より先に実行される可能性があるため、初期化操作に使用できます。組み合わせDMLトリガーに BEFORE STATEMENT 部分も AFTER STATEMENT 部分もなく、かつそのトリガー文がいかなる行にも影響しない場合、トリガーは決して発生しません。
組み合わせDMLトリガーの制限
組み合わせDMLトリガーには以下の制限があります:
OLD、NEW、PARENTは、宣言部、BEFORE STATEMENT部分、またはAFTER STATEMENT部分には使用できません。NEWの値を変更できるのはBEFORE EACH ROW部分のみです。- ある時間区間では、別の時間区間で発生した例外を処理できません。
- 時間区間内に
GOTO文が含まれる場合、GOTO文のターゲット位置は同一の時間区間内になければなりません。
組み合わせDMLトリガーの利点
組み合わせDMLトリガーは、バッチSQLの使用や、トリガー文が多くの行に影響を及ぼすシナリオにおいて、パフォーマンス上の利点があります。
以下の例では、この文が4つの時間区間を持つ組み合わせDMLトリガーをトリガーしたと仮定します。tbl1 テーブルの col1 列が col2 より大きい各行に対して、トリガーの BEFORE EACH ROW および AFTER EACH ROW 部分を実行します。ただし、BEFORE STATEMENT 部分は INSERT 文の実行前にのみ実行され、AFTER STATEMENT 部分は INSERT 文の実行後にのみ実行されます。
INSERT INTO tbl2
SELECT col1
FROM tbl1
WHERE tbl1.col1 > col2;
さらに、組み合わせDMLトリガーをバッチ挿入文と組み合わせて使用することもできます。組み合わせDMLトリガーは行を累積した後、他のテーブルに送信することで、定期的なデータのバッチ挿入を実現できます。複合DMLトリガーを使用することで、変異テーブルエラー(エラーコード OBE-04091)を回避することもできます。
例
組み合わせトリガーを使用して、変更情報をテーブルのサブテーブルに記録します。
obclient> CREATE TABLE emp_sal (
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);
Query OK, 0 rows affected
obclient> delimiter /
obclient> CREATE OR REPLACE TRIGGER maintain_emp_sal
FOR UPDATE OF salary ON employees
COMPOUND TRIGGER
threshhold CONSTANT SIMPLE_INTEGER := 3;
TYPE sal_typ IS TABLE OF emp_sal%ROWTYPE INDEX BY SIMPLE_INTEGER;
sal sal_typ;
idx SIMPLE_INTEGER := 0;
PROCEDURE flush_proc IS
n CONSTANT SIMPLE_INTEGER := sal.count();
BEGIN
FORALL j IN 1..n
INSERT INTO emp_sal 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 >= threshhold THEN
flush_proc();
END IF;
END AFTER EACH ROW;
-- AFTER STATEMENT タイムスロット:
AFTER STATEMENT IS
BEGIN
flush_proc();
END AFTER STATEMENT;
END maintain_emp_sal;
/
Query OK, 0 rows affected
obclient> delimiter ;
obclient> SET SERVEROUTPUT ON;
Query OK, 0 rows affected
/* 部門50の各従業員の給与を8%引き上げる */
obclient> UPDATE employees
SET salary = salary * 0.8
WHERE department_id = 50;
Query OK, 10 rows affected
Rows matched: 10 Changed: 10 Warnings: 0
3行をフラッシュ
3行をフラッシュ
7行をフラッシュ
Flushed 7 rows
3行をフラッシュ
1行をフラッシュ
3行をフラッシュ
Flushed 3 rows
/* 3秒間待機する */
obclient> BEGIN
DBMS_LOCK.SLEEP(3);
END;
/
Query OK, 1 row affected(3.01 sec)
/* 部門50の各従業員の給与を1.1%引き上げる */
obclient> UPDATE employees
SET salary = salary * 1.1
WHERE department_id = 50;
Query OK, 10 rows affected
Rows matched: 10 Changed: 10 Warnings: 0
3行をフラッシュ
3行をフラッシュ
7行をフラッシュ
Flushed 7 rows
3行をフラッシュ
1行をフラッシュ
3行をフラッシュ
Flushed 3 rows
/* emp_sal テーブルの従業員テーブルの変更状況を確認する */
obclient> SELECT emp_id, count(*) num
FROM emp_sal
GROUP BY emp_id;
+--------+------+
| EMP_ID | NUM |
+--------+------+
| 120 | 2 |
| 121 | 2 |
| 122 | 2 |
| 123 | 2 |
| 124 | 2 |
| 125 | 2 |
| 126 | 2 |
| 127 | 2 |
| 128 | 2 |
| 129 | 2 |
+--------+------+
10 rows in set