組み合わせ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