トリガー内の変更テーブルではDMLステートメントを使用できないことがわかっています(または少なくとも知っていました)。 Oracleドキュメント からの抜粋:
変更テーブルは、UPDATE、DELETE、またはINSERTステートメントによって変更されるテーブル、またはDELETE CASCADE制約の影響によって更新される可能性があるテーブルです。
トリガーステートメントを発行したセッションは、変更テーブルをクエリまたは変更できません。この制限により、トリガーが一貫性のないデータセットを参照するのを防ぎます。
ただし、SQL DeveloperまたはSQL * Plusを使用してinsert into emp
を実行したときに、このデモトリガーが「変更テーブル」エラーで失敗しない理由を理解できません。
CREATE OR REPLACE TRIGGER emp_bri
BEFORE INSERT ON emp
FOR EACH ROW
BEGIN
SELECT max(id) + 1 INTO :NEW.id FROM emp;
UPDATE emp SET salary = 5000;
END emp_bri;
挿入は次のid
値で正常に完了し、すべてのemp
レコードを更新します。 Oracle Database 11g Enterprise Editionリリース11.2.0.1.0を使用しています。複合トリガーについて読みましたが、サンプルではそれらを使用していません。
例外があります。テーブルにbefore insert
の行レベルのトリガーを定義し、単一の行INSERT
ステートメントを発行しても、table is mutating
エラーは発生しません。ただし、同じ種類のトリガーを定義して複数行のINSERT
ステートメントを発行すると、エラーが発生します。次に例を示します。
SQL> create table TB_TR_TEST(
2 col1 number,
3 col2 number
4 )
5 ;
Table created
SQL> create or replace trigger TR_TB_TR_TEST
2 before insert on TB_TR_TEST
3 for each row
4 begin
5 SELECT max(col1) + 1 INTO :NEW.col1
6 FROM TB_TR_TEST;
7 UPDATE TB_TR_TEST SET col2 = 5000;
8 end;
9 /
Trigger created
次に、単一行のinsert
ステートメントを示します。これにより、変換テーブルエラーは発生しません。
SQL> insert into TB_TR_TEST(col1, col2) values(1,2);
1 row inserted
SQL> insert into TB_TR_TEST(col1, col2) values(3,5);
1 row inserted
SQL> commit;
Commit complete
次に、複数行の挿入ステートメントを示します。これにより、変更テーブルエラーが発生します。
SQL> insert into TB_TR_TEST(col1, col2)
2 select 1, 2
3 from dual;
insert into TB_TR_TEST(col1, col2)
select 1, 2
from dual
ORA-04091: table HR.TB_TR_TEST is mutating, trigger/function may not see it
ORA-06512: at "HR.TR_TB_TR_TEST", line 2
ORA-04088: error during execution of trigger 'HR.TR_TB_TR_TEST'