トリガーで変更テーブルエラーが発生しないのはなぜですか?


11

トリガー内の変更テーブルでDMLステートメントを使用できないことはわかっています(または少なくとも知っていました)。Oracleのドキュメントからの抜粋:

変更テーブルは、UPDATE、DELETE、またはINSERTステートメントによって変更されるテーブル、またはDELETE CASCADE制約の影響によって更新される可能性があるテーブルです。

トリガーステートメントを発行したセッションは、変更テーブルをクエリまたは変更できません。この制限により、トリガーが一貫性のないデータセットを参照するのを防ぎます。

ただし、insert into empSQL DeveloperまたはSQL * Plusを使用してこのデモトリガーが「変更テーブル」エラーで失敗しない理由を理解できません。

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を使用しています。複合トリガーについて読みましたが、サンプルでは使用していません。


1
あなたの質問に関係のない、しかし:ないないで使用するselect max(id)ユニークな番号を割り当てます。しないでください。それは単に不正確であり、同様にスケーリングしません。
a_horse_with_no_name 2012年

はい、私はそれを知っています:)この例ではおそらく例はあまり良くありません...自動インクリメント値はシーケンスとトリガーを使用して確実に実装する必要があります。
センチュリオン

これは確かに奇妙です。ところで:これはSQLFiddleの例ですsqlfiddle.com/#!4/9e59f/2
a_horse_with_no_name

情報を共有してくれてありがとう、クールなリンク。そのようなOracle SQLテストWebサイトがあることを知りませんでした:)
Centurion

回答:


12

例外があります。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'

これが原因のようです。マニュアルにこの動作のリファレンスがありますか?
a_horse_with_no_name

@a_horse_with_no_name support.oracle.comにアクセスできる場合は、ID 132569.1ORA-4091 on BEFORE ROW TRIGGER with INSERT .. into SELECT statement)を検索します。
Nicholas Krasnov

2
ありがとう。興味深い十分なこの例外は8Iで文書化しているようだマニュアル(!):docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/...(セクション「『変異と制約テーブル』)私は」することができますt現在のマニュアルでそのステートメントを見つけます
a_horse_with_no_name '25
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.