トリガーはOceanBaseデータベースが提供する機能であり、ストアドプロシージャや関数と同様に、宣言、実行、例外処理のプロセスを含むPLブロックであり、PL言語で記述されたコンパイル済みのストレージユニットです。
トリガーは独立したオブジェクトであり、特定のトリガー文が実行されると自動的かつ暗黙的に起動します。また、トリガーはパラメータを受け取ることができません。ここでいうトリガー文とは、データベースのテーブルに対するINSERT、UPDATE、およびDELETE操作を指します。
トリガーの利点
トリガーを適切に使用することで、アプリケーションの構築とデプロイがよりシンプルかつ堅牢になります。
トリガーを使用して、すべてのクライアントプログラムに基盤となる業務ロジックの実行を強制できます。例えば、複数のクライアントアプリケーションが同一のテーブルにアクセスする場合、そのテーブルに設定されたトリガーがデータ挿入時に実行すべきロジックを保証していれば、その業務ロジックは各クライアントで個別に実行する必要はありません。アプリケーションはトリガーを無視することができないため、自動的にトリガー内の業務ロジックを使用します。
必要な場合にのみトリガーを使用し、過度な使用は避けてください。トリガーを過度に使用すると、複雑な相互依存関係が生じ、大規模なアプリケーションではメンテナンスが困難になります。例えば、トリガーが実行される際に発生するSQL文が他のトリガーを引き金として作動させ、カスケードトリガーを引き起こす可能性があります。これにより、予期しない結果が発生する可能性があります。
トリガーの種類
OceanBaseデータベースでは、以下の種類のトリガーを作成できます:
行レベルトリガー
行レベルトリガーはエンティティテーブルに作成され、テーブルがトリガー文の影響を受けるたびに1回ずつ実行されます。例えば、1つの文で複数行のデータを更新する場合、影響を受ける各行ごとにトリガーが1回ずつ実行されます。トリガー文がいずれの行データにも影響しない場合は、トリガーは実行されません。
ステートメントレベルトリガー
ステートメントレベルトリガーはエンティティテーブルに作成され、トリガー文が実行されるたびに自動的に1回ずつ実行されます。トリガー文がテーブル内のデータに影響したかどうかに関係ありません。例えば、1つの文でテーブル内の100件のデータを更新した場合、ステートメントレベルの
UPDATEトリガーは1回だけ実行されます。INSTEAD OFトリガー
INSTEAD OFトリガーはビューに作成され、ビューに対してトリガー文が実行されると自動的に実行されます。INSTEAD OFトリガーは、DML文では直接変更できないビューを変更するために使用できます。
組み合わせDMLトリガー
組み合わせDMLトリガーはテーブルまたはビューに作成でき、複数のタイミングでの実行をサポートします。組み合わせトリガーは各時間点ごとにセクションに分かれており、各時間帯には独立した実行可能部分と例外処理部分(オプション)が含まれます。
システムトリガー トリガーイベントの違いにより、システムトリガーは大きく2つのカテゴリに分けられます。すなわち、DDLイベントトリガーとデータベースイベントトリガーです。DDLイベントトリガーとは、DDLの実行によってトリガーされるトリガーを指し、データベースイベントトリガーとは、データベースイベントによってトリガーされるトリガーを指します。ログオンとログオフはデータベースイベントに属するため、これら2種類のトリガーはデータベースイベントトリガーに分類され、それぞれユーザーログイン後とユーザーログアウト前に実行されます。
トリガーの実行タイミング
トリガーの実行タイミングを定義できます。実行タイミングとは、トリガー操作がトリガーステートメントの前に実行されるか後に実行されるかを指します。
行レベルトリガーとステートメントレベルトリガーでは、以下の実行タイミングを指定できます:
トリガーステートメントの実行前
各データ行がトリガーステートメントによって変更される前
各データ行がトリガーステートメントによって変更された後
トリガーステートメントの実行後
ステートメントレベルおよび行レベルのトリガーについて、BEFOREトリガーはデータの変更前にセキュリティを強化し、業務ルールを実行するのに適しています。AFTERトリガーは操作ログの記録に非常に適しています。
単純トリガーの実行タイミングは以下の4種類です:
イベント実行前(ステートメントレベルのBEFOREトリガー)
イベント実行後(ステートメントレベルのAFTERトリガー)
各行がイベント実行の影響を受ける前(行レベルのBEFOREトリガー)
各行がイベント実行の影響を受けた後(行レベルのAFTERトリガー)
システムトリガーは、ユーザーログイン時やすべてのユーザーがログインした際にトリガーされるように、スキーマ(user)またはデータベース上に作成できます。ON user_name.SCHEMA を指定することで、特定のユーザーがログインした際にトリガーされるように設定できます。user_name を指定しない場合、デフォルトでトリガーを作成したユーザーがログインした際にトリガーされます。
トリガーの実行順序は以下のとおりです:
同一タイプのトリガー間での実行順序は不確定であり、現在トリガーの実行順序を指定する機能はサポートされていません。
1つのDMLステートメントが複数の単純トリガーをトリガーする可能性があります。その実行の優先順序は以下のとおりです:ステートメントレベルBEFOREトリガー -> 行レベルBEFOREトリガー -> 行レベルAFTERトリガー -> ステートメントレベルAFTERトリガー。
注意
OceanBase データベース V2.2.7x およびそれ以前のバージョンでは、テーブル上の行レベルトリガーのみがサポートされています。
トリガーの作成
トリガーを作成するための基本的な構文は以下のとおりです:
CREATE [OR REPLACE] TRIGGER trigger_name triggering_statement
[trigger_restriction]
BEGIN
triggered_action;
END
triggering_statementL:
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column ...]]}
ON [schema.] table_name
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
FOR EACH ROW
[WHEN condition]
[FOLLOWS | PRECEDES] other_trigger_name
トリガーの基本構造は以下のとおりです:
トリガー名(Trigger Name)
同一データベース内で、トリガー名は一意である必要があります。例えば、トリガー名はrow_triggger_on_employeesなどにすることができます。
トリガー文(Triggering Statement)
トリガー文とは、トリガーを呼び出すSQL文です。例えば、ユーザーがテーブルを更新する場合などです。
トリガー制約(Trigger Restriction)
トリガー制約とは、ブール式を定義し、その式が真の場合にのみトリガーを実行する条件です。例えば、従業員テーブル上のトリガーで、北京在住の従業員のみがこのトリガーを実行できるように制限を定義することができます。
トリガー動作(Trigger Action)
トリガー動作とは、トリガー文が実行され、かつトリガー制約が真である場合に実行されるトリガー内部のコードブロックです。例えば、従業員テーブルにデータを挿入する処理などです。
トリガーの作成例
テーブル emp_msg に対して、INSERT、UPDATE、DELETE ステートメントを実行するたびにトリガーが発生するようにトリガーを作成します。
emp_msg テーブルにデータを挿入すると、同時に employees テーブルにも1件のデータが挿入されます。emp_msg テーブルからデータを削除すると、employees テーブルから id が同じデータも削除されます。emp_msg テーブルのデータを更新すると、employees テーブルの id が同じデータも更新されます。
CREATE TABLE employees (id INT, name VARCHAR2(20), WORK_YEAR int);
CREATE TABLE emp_msg (id INT PRIMARY KEY, name VARCHAR2(20), address VARCHAR2(100));
CREATE OR REPLACE TRIGGER tri_emp_msg BEFORE INSERT OR UPDATE OR DELETE ON emp_msg
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO employees VALUES (:NEW.id, :NEW.name, 0);
ELSIF DELETING THEN
DELETE FROM employees WHERE id = :OLD.id;
ELSE
UPDATE employees SET name = :NEW.name WHERE id = :NEW.id;
END IF;
END;
/
トリガーの作成後、以下の例のDMLステートメントを実行します:
obclient> INSERT INTO emp_msg VALUES (1, 'Curry', 'BeiJing');
Query OK, 1 row affected
obclient> SELECT * FROM emp_msg WHERE id = 1;
+----+-------+---------+
| ID | NAME | ADDRESS |
+----+-------+---------+
| 1 | Curry | BeiJing |
+----+-------+---------+
1 row in set
obclient> SELECT * FROM employees WHERE id = 1;
+------+-------+-----------+
| ID | NAME | WORK_YEAR |
+------+-------+-----------+
| 1 | Curry | 0 |
+------+-------+-----------+
1 row in set
obclient> UPDATE emp_msg SET name = 'Stephen Curry' WHERE id = 1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0
obclient> SELECT * FROM emp_msg WHERE id = 1;
+----+---------------+---------+
| ID | NAME | ADDRESS |
+----+---------------+---------+
| 1 | Stephen Curry | BeiJing |
+----+---------------+---------+
1 row in set
obclient> SELECT * FROM employees WHERE id = 1;
+------+---------------+-----------+
| ID | NAME | WORK_YEAR |
+------+---------------+-----------+
| 1 | Stephen Curry | 0 |
+------+---------------+-----------+
1 row in set
obclient> DELETE FROM emp_msg WHERE id = 1;
Query OK, 1 row affected
obclient> SELECT * FROM emp_msg WHERE id = 1;
Empty set
obclient> SELECT * FROM employees WHERE id = 1;
Empty set