Oracle PL/SQLトリガー:&複合型の代わりに

⚡ スマートサマリー

PL/SQLトリガーは、 Oracle DML、DDL、またはデータベースイベントが発生すると、エンジンが自動的に起動します。これらはデータの整合性を維持し、ルールを適用し、監査をサポートします。また、BEFORE、AFTER、INSTEAD OF、および複合型が含まれます。

  • 🔔 トリガーの定義: トリガーは保存されたプログラムです Oracle 指定されたDML、DDL、またはデータベースイベントが発生すると、エンジンが自動的に起動します。
  • 🎯 トリガーの種類: トリガーは、タイミング(BEFORE、AFTER、INSTEAD OF)、レベル(STATEMENT、ROW)、およびイベント(DML、DDL、DATABASE)によって分類されます。
  • 🔁 :新旧: 行レベルトリガーは、:NEW句と:OLD句を使用して、DMLステートメントの前後の列の値を読み取ります。
  • 🪟 トリガーの代わりに: INSTEAD OFトリガーを使用すると、通常は更新できない複雑なビューを、その基となるテーブルを操作することによって変更できるようになります。
  • 🧩 複合トリガー: 複合トリガーは、4つのタイミングポイントすべての動作を1つのトリガー本体内に統合したものです。
  • 🤖 AI 支援: GitHub CopilotなどのAIアシスタントは、コメントからBEFORE、AFTER、INSTEAD OF、および複合トリガーを下書きします。

Oracle PL/SQLトリガー(INSTEAD OFトリガーおよび複合トリガータイプを含む)

PL/SQLのトリガーとは何ですか?

トリガーは保存されます PL / SQLの によって発火されるプログラム Oracle エンジンが自動的に DMLステートメント テーブルに対して挿入、更新、削除などの操作が実行されるとき、または何らかのイベントが発生したときにトリガーが実行されます。トリガーの場合に実行されるコードは、要件に応じて定義できます。トリガーを起動するイベントと実行タイミングを選択できます。トリガーの目的は、データベース上の情報の整合性を維持することです。

トリガーの利点

トリガーの利点は次のとおりです。

  • 一部の派生列値を自動的に生成する
  • 参照整合性の強制
  • イベントのログ記録とテーブルアクセスに関する情報の保存
  • 会計監査
  • Syncテーブルの大量のレプリケーション
  • セキュリティ権限の強制
  • 無効なトランザクションの防止

トリガーの種類 Oracle

トリガーは次のパラメータに基づいて分類できます。

タイミングに基づく分類

  • トリガー前: 指定されたイベントが発生する前に発火します。
  • トリガー後: 指定されたイベントが発生した後に発火します。
  • トリガーの代わりに: 特殊なタイプです。詳細は後述のトピックで説明します。(DML専用)

レベルに基づく分類

  • ステートメントレベルのトリガー: 指定されたイベントステートメントに対して、1回だけ実行されます。
  • 行レベルトリガー: 指定されたイベントで影響を受けたレコードごとに発生します。(DMLの場合のみ)

イベントに基づく分類

  • DMLトリガー: DMLイベント(INSERT/UPDATE/DELETE)が指定されたときに発生します。
  • DDLトリガー: DDLイベント(CREATE/ALTER)が指定されたときに発生します。
  • データベーストリガー: データベースイベント(ログオン/ログオフ/起動/シャットダウン)が指定されたときに発生します。

つまり、各トリガーは上記のパラメータの組み合わせによって構成されます。

トリガーの作成方法

以下にトリガーを作成するための構文を示します。以下のスクリーンショットは、このトリガー作成構文を示しています。 Oracle.

BEFORE、AFTER、INSTEAD OF オプションを使用したトリガー作成構文 Oracle PL / SQLの

CREATE [ OR REPLACE ] TRIGGER <trigger_name> 

[BEFORE | AFTER | INSTEAD OF ]

[INSERT | UPDATE | DELETE......]

ON<name of underlying object>

[FOR EACH ROW] 

[WHEN<condition for trigger to get execute> ]

DECLARE
<Declaration part>
BEGIN
<Execution part> 
EXCEPTION
<Exception handling part> 
END;

構文の説明:

  • 上記の構文は、トリガーの作成時に存在するさまざまなオプションのステートメントを示しています。
  • BEFORE/AFTERはイベントのタイミングを指定します。
  • 挿入/更新/ログオン/作成など。 トリガーを起動する必要があるイベントを指定します。
  • ON句は、前述のイベントが有効なオブジェクトを指定します。例えば、DMLトリガーの場合、これはDMLイベントが発生する可能性のあるテーブル名になります。
  • 「FOR EACH ROW」コマンドは、行レベルのトリガーを指定します。
  • WHEN句は、トリガーが作動する必要がある追加条件を指定します。
  • 宣言部、実行部、例外処理部は他のものと同じです PL/SQLブロック宣言部分と 例外処理 一部はオプションです。

:NEW 句と :OLD 句

行レベルのトリガーでは、トリガーは関連する行ごとに起動されます。 また、DML ステートメントの前後の値を知る必要がある場合もあります。

Oracle 行レベルトリガーには、これらの値を保持するための2つの句が用意されています。これらの句を使用することで、トリガー本体内で古い値と新しい値を参照できます。

  • :新しい トリガーの実行中に、ベーステーブル/ビューの列に新しい値を保持します。
  • :古い トリガー実行中に、ベーステーブル/ビューの列の古い値を保持します。

この句は、DMLイベントに基づいて使用する必要があります。以下の表は、どの句がどのDMLステートメント(INSERT/UPDATE/DELETE)に対して有効であるかを示しています。

INSERT UPDATE DELETE
:新しい VALID VALID 無効です。削除対象のケースに新しい値がありません。
:古い 無効です。挿入ケースに古い値が存在しません。 VALID VALID

トリガーの代わりに

「INSTEAD OFトリガー」は特殊なタイプのトリガーです。DMLトリガーでのみ使用され、複雑なビューでDMLイベントが発生する場合に使用されます。

3つの基本テーブルからビューを作成する例を考えてみましょう。このビューに対してDMLイベントが発行されると、データが3つの異なるテーブルから取得されるため、ビューは無効になります。このような場合、INSTEAD OFトリガーが使用されます。INSTEAD OFトリガーは、指定されたイベントに対してビューを変更するのではなく、基本テーブルを直接変更するために使用されます。

例1: この例では、2つの基本テーブルから複雑なビューを作成します。ここで、Table_1は従業員テーブル、Table_2は部署テーブルです。

次に、INSTEAD OFトリガーを使用して、この複雑なビューのロケーション詳細を更新する方法を見ていきます。また、トリガーで:NEWと:OLDがどのように役立つかも見ていきます。この例は、以下の手順で行います。

  • ステップ1:適切な列を持つテーブル「emp」と「dept」を作成する
  • ステップ2:サンプル値でテーブルを埋める
  • ステップ3:上記で作成したテーブルのビューを作成する
  • ステップ4:INSTEAD OFトリガーの前にビューを更新する
  • ステップ5:INSTEAD OFトリガーの作成
  • ステップ6:INSTEAD OFトリガー後のビューの更新

ステップ1)適切な列を持つテーブル「emp」と「dept」を作成します。

以下のスクリーンショットは、「emp」と「dept」の基本テーブルの作成を示しています。 Oracle.

emp および dept ベース テーブルを作成する Oracle INSTEAD OFトリガーの例

CREATE TABLE emp(
emp_no NUMBER,
emp_name VARCHAR2(50),
salary NUMBER,
manager VARCHAR2(50),
dept_no NUMBER);
/

CREATE TABLE dept(
Dept_no NUMBER,
Dept_name VARCHAR2(50),
LOCATION VARCHAR2(50));
/

Code 説明

  • Code 1行目~7行目: テーブル「emp」の作成。
  • Code 8行目~12行目: テーブル「dept」の作成。

出力:

Table Created

ステップ2) さて、テーブルを作成したので、次にサンプル値を入力してみます。

以下のスクリーンショットは、「dept」テーブルと「emp」テーブルに挿入されるサンプル行を示しています。

サンプル部門と従業員の行を挿入します Oracle PL / SQLの

BEGIN
INSERT INTO DEPT VALUES(10,'HR','USA');
INSERT INTO DEPT VALUES(20,'SALES','UK');
INSERT INTO DEPT VALUES(30,'FINANCIAL','JAPAN');
COMMIT;
END;
/

BEGIN
INSERT INTO EMP VALUES(1000,'XXX',15000,'AAA',30);
INSERT INTO EMP VALUES(1001,'YYY',18000,'AAA',20) ;
INSERT INTO EMP VALUES(1002,'ZZZ',20000,'AAA',10);
COMMIT;
END;
/

Code 説明

  • Code 13行目~19行目: 「dept」テーブルにデータを挿入しています。
  • Code 20行目~26行目: 「emp」テーブルにデータを挿入しています。

出力:

PL/SQL procedure completed

ステップ3) 上記で作成したテーブルのビューを作成します。

以下のスクリーンショットは、複雑なビューが作成され、その後クエリが実行されている様子を示しています。

empとdeptを結合した複合ビューguru99_emp_viewの作成とクエリ

CREATE VIEW guru99_emp_view(
Employee_name,dept_name,location) AS
SELECT emp.emp_name,dept.dept_name,dept.location
FROM emp,dept
WHERE emp.dept_no=dept.dept_no;
/
SELECT * FROM guru99_emp_view;

Code 説明

  • Code 27行目~32行目: 「guru99_emp_view」ビューを作成します。
  • Code 33行目: guru99_emp_view をクエリしています。

出力:

View created
従業員名 DEPT_NAME 位置
ZZZ HR USA
YYY セール UK
XXX 財務 JAPAN

ステップ4) INSTEAD OFトリガーの前にビューを更新します。

以下のスクリーンショットは、複合ビューの更新試行と、その結果発生したエラーを示しています。

INSTEAD OFトリガーの前にORA-01779エラーで失敗する複雑なビューに関する最新情報

BEGIN
UPDATE guru99_emp_view SET location='FRANCE' WHERE employee_name='XXX';
COMMIT;
END;
/

Code 説明

  • Code 34行目~38行目: 「XXX」の場所を「FRANCE」に更新してください。複合ビューに対してDMLステートメントを直接実行することは許可されていないため、例外が発生しました。

出力:

ORA-01779: cannot modify a column which maps to a non key-preserved table

ORA-06512: at line 2

ステップ5) 前の手順でビューを更新する際に発生したエラーを回避するため、この手順では「INSTEAD OF トリガー」を使用します。

以下のスクリーンショットは、INSTEAD OFトリガーの作成を示しています。

複合ビューで guru99_view_modify_trg INSTEAD OF トリガーを作成する

CREATE TRIGGER guru99_view_modify_trg
INSTEAD OF UPDATE
ON guru99_emp_view
FOR EACH ROW
BEGIN
UPDATE dept
SET location=:new.location
WHERE dept_name=:old.dept_name;
END;
/

Code 説明

  • Code 39行目: 行レベルで「guru99_emp_view」ビューの「UPDATE」イベントに対するINSTEAD OFトリガーを作成します。このトリガーには、ベーステーブル「dept」内の場所を更新するための更新ステートメントが含まれています。
  • Code 44行目: 更新ステートメントでは、「:NEW」と「:OLD」を使用して、更新前と更新後の列の値を取得します。

出力:

Trigger Created

ステップ6) INSTEAD OFトリガー後のビューの更新。これでエラーは発生しなくなります。「INSTEAD OFトリガー」がこの複雑なビューの更新処理を処理するためです。コードが実行されると、従業員XXXの所在地が「日本」から「フランス」に更新されます。

以下のスクリーンショットは、INSTEAD OFトリガーによる更新が成功し、更新されたビューが表示されたことを示しています。

INSTEAD OFトリガーによるビューの更新が成功し、フランスの場所が表示されました。

BEGIN
UPDATE guru99_emp_view SET location='FRANCE' WHERE employee_name='XXX';
COMMIT;
END;
/
SELECT * FROM guru99_emp_view;

Code 説明:

  • Code 49行目~53行目: 「XXX」の場所を「FRANCE」に更新します。「INSTEAD OF」トリガーがビューに対する実際の更新ステートメントを停止し、ベーステーブルの更新を実行したため、更新は成功しました。
  • Code 55行目: 更新されたレコードを確認しています。

出力:

PL/SQL procedure successfully completed
従業員名 DEPT_NAME 位置
ZZZ HR USA
YYY セール UK
XXX 財務 フランス

複合トリガー

複合トリガーとは、単一のトリガー本体内で4つのタイミングポイントそれぞれに対してアクションを指定できるトリガーです。サポートされる4つのタイミングポイントは以下のとおりです。

  • BEFORE STATEMENT – レベル
  • BEFORE ROW – レベル
  • AFTER ROW – レベル
  • ステートメント後の – レベル

異なるタイミングのアクションを同じトリガーに組み合わせる機能を提供します。

以下のスクリーンショットは、4つのタイミングセクションを含む複合トリガー構文を示しています。

BEFOREおよびAFTERステートメントと行タイミングセクションを示す複合トリガー構文

CREATE [ OR REPLACE ] TRIGGER <trigger_name>
FOR
[INSERT | UPDATE | DELETE.......]
ON <name of underlying object>
<Declarative part>
BEFORE STATEMENT IS
BEGIN
<Execution part>;
END BEFORE STATEMENT;

BEFORE EACH ROW IS
BEGIN
<Execution part>;
END EACH ROW;

AFTER EACH ROW IS
BEGIN
<Execution part>;
END AFTER EACH ROW;

AFTER STATEMENT IS
BEGIN
<Execution part>;
END AFTER STATEMENT;
END;

構文の説明:

  • 上記の構文は、「複合」トリガーの作成方法を示しています。
  • 宣言部分は、トリガー本体内のすべての実行ブロックに共通です。
  • これら4つのタイミングブロックは、どのような順序でも構いません。4つすべてを用意する必要はありません。必要なタイミングのみに対応する複合トリガーを作成することも可能です。

例1: この例では、給与列にデフォルト値の5000を自動入力するトリガーを作成します。

以下のスクリーンショットは、複合トリガーの例とその出力を示しています。

複合トリガーにより、給与列にデフォルト値5000が自動入力されます。

CREATE TRIGGER emp_trig
FOR INSERT
ON emp
COMPOUND TRIGGER
BEFORE EACH ROW IS
BEGIN
:new.salary:=5000;
END BEFORE EACH ROW;
END emp_trig;
/
BEGIN
INSERT INTO EMP VALUES(1004,'CCC',15000,'AAA',30);
COMMIT;
END;
/
SELECT * FROM emp WHERE emp_no=1004;

Code 説明:

  • Code 2行目~10行目: 複合トリガーを作成します。これは、BEFORE ROW レベルのタイミングに合わせて作成され、給与にデフォルト値 5000 を設定します。これにより、レコードをテーブルに挿入する前に、給与がデフォルト値「5000」に変更されます。
  • Code 11行目~14行目: レコードを「emp」テーブルに挿入します。
  • Code 16行目: 挿入されたレコードを検証しています。

出力:

Trigger created

PL/SQL procedure successfully completed.
EMP_NAME EMP_NO 給料 MANAGER DEPT_NO
CCC 1004 5000 単4 30

トリガーの有効化と無効化

トリガーは有効化または無効化できます。トリガーを有効化または無効化するには、トリガーに対して、無効化または有効化を行うALTER(DDL)ステートメントを指定する必要があります。

以下に、トリガーを有効化/無効化するための構文を示します。

ALTER TRIGGER <trigger_name> [ENABLE|DISABLE];
ALTER TABLE <table_name> [ENABLE|DISABLE] ALL TRIGGERS;

構文の説明:

  • 最初の構文は、単一のトリガーを有効/無効にする方法を示しています。
  • XNUMX 番目のステートメントは、特定のテーブルのすべてのトリガーを有効または無効にする方法を示しています。

よくあるご質問

ORA-04091「テーブル変更エラー」は、行レベルトリガーが、自身を起動したテーブルと同じテーブルを照会または変更しようとしたときに発生します。このエラーを回避するには、複合トリガー、ステートメントレベルトリガーを使用するか、行をパッケージコレクションに保持してください。

トリガーは、DML、DDL、またはデータベースイベントが発生したときに自動的に起動し、パラメーターを受け取らず、何も返しません。 ストアドプロシージャ 明示的に呼び出した場合にのみ実行され、パラメータを受け取り、値を返すことができます。

トリガーを完全に削除するには、DROP TRIGGER trigger_name ステートメントを使用します。無効化はトリガーを保持したまま発火を停止しますが、削除はトリガーを完全に削除します。ping 定義を完全に削除するため、そのロジックが再び必要になった場合は、定義を再作成する必要があります。

独自のトリガーについてはデータディクショナリビューUSER_TRIGGERSを、アクセス可能なすべてのトリガーについてはALL_TRIGGERSを照会してください。これらのビューには、トリガー名、タイプ、トリガーイベント、ベースオブジェクト、およびステータスが表示され、既存のトリガーの監査に役立ちます。

直接的にはそうではない。なぜなら、トリガーは発火ステートメントを共有するからである。 トランザクション独立してコミットするには、トリガーまたはトリガーが呼び出すプロシージャを PRAGMA AUTONOMOUS_TRANSACTION で宣言します。これにより、作業が別のトランザクションで実行され、それ自体でコミットされます。

作業前 Oracle 11g では、同じタイプのトリガーの実行順序は保証されていませんでした。11g 以降では、CREATE TRIGGER ステートメントの FOLLOWS 句を使用することで、トリガーの実行順序を指定できるようになり、実行順序が確定されます。

Yes. GitHubコパイロット コメントからのドラフト BEFORE、AFTER、INSTEAD OF、および:NEWと:OLD参照を含む複合トリガー。 Rev生成されたトリガーをデプロイする前に、タイミング、WHEN条件、およびミューテーションテーブルのリスクを確認してください。

AIアシスタントは、トリガーをスキャンして、テーブル変更リスク、:NEWまたは:OLD処理の欠落、再帰的なトリガー発火、DML処理を遅くする複雑なロジックなどを検出します。この機械学習によるレビューは、脆弱なトリガーを特定し、コードが本番環境にデプロイされる前に、ステートメントレベルまたは複合的な書き換えを提案します。