Perché NON ricevo un errore di tabella mutante nel trigger?


11

È noto (o almeno era noto) che non è possibile utilizzare le istruzioni DML su una tabella mutante all'interno di un trigger. Un estratto dalla documentazione di Oracle :

Una tabella mutante è una tabella che viene modificata da un'istruzione UPDATE, DELETE o INSERT o una tabella che potrebbe essere aggiornata dagli effetti di un vincolo DELETE CASCADE.

La sessione che ha emesso l'istruzione trigger non può eseguire query o modificare una tabella mutante. Questa restrizione impedisce a un trigger di vedere un insieme incoerente di dati.

Tuttavia, non riesco a capire perché questo trigger dimostrativo non stia fallendo con un errore di "tabella mutante" quando eseguo un insert into emputilizzo di SQL Developer o 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;

L'inserimento si completa correttamente con il idvalore successivo e aggiorna tutti i emprecord. Sto utilizzando Oracle Database 11g Enterprise Edition versione 11.2.0.1.0. Ho letto sui trigger composti ma il campione non li utilizza.


1
Non correlato alla tua domanda, ma: NON utilizzare select max(id)per assegnare numeri univoci. Non farlo. È semplicemente errato e non si ridimensionerà.
a_horse_with_no_name

Sì, lo so :) L'esempio probabilmente non è molto buono in questo caso ... I valori di incremento automatico dovrebbero essere implementati definitivamente usando sequenze e trigger.
Centurione,

Questo è sicuramente strano. A proposito: ecco un esempio SQLFiddle sqlfiddle.com/#!4/9e59f/2
a_horse_with_no_name

Grazie per aver condiviso informazioni, link interessante. Non sapevo che ci fosse un tale sito Web di test di Oracle SQL :)
Centurion

a_horse_with_no_name: Un altro esempio: Fiddle-test-2 (SET stipendio = stipendio + 10)
ypercubeᵀᴹ

Risposte:


12

C'è un'eccezione Quando si definisce un before inserttrigger a livello di riga su una tabella e si emette una singola INSERTistruzione di riga , l' table is mutatingerrore non verrà generato. Ma se si definisce lo stesso tipo di trigger e si emette INSERTun'istruzione multi-riga , l'errore verrà generato. Ecco un esempio:

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

Ecco insertun'istruzione a riga singola , che non genererà errori nella tabella di muting:

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

Ecco un'istruzione insert a più righe, che genererà un errore di tabella mutante:

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'

Questo sembra essere il colpevole. Hai un riferimento nel manuale per questo comportamento?
a_horse_with_no_name

@a_horse_with_no_name se hai accesso a support.oracle.com, cerca ID 132569.1( ORA-4091 on BEFORE ROW TRIGGER with INSERT .. into SELECT statement).
Nicholas Krasnov,

2
Grazie. Abbastanza interessante questa eccezione sembra essere documentata solo nei manuali 8i (!): Docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/… (la sezione " " Mutare e vincolare le tabelle ") Posso ' Non trovo questa affermazione nei manuali attuali.
a_horse_with_no_name
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.