Pular para o conteúdo

Fóruns SQL e PL/SQL Trigger Só Executa Primeiro Bloco do Programa Trigger Só Executa Primeiro Bloco do Programa

#92074
fsitja
Participante

    Você não pode usar pragma autonomous transaction para isso, esse recurso não foi criado para contornar ORA-04091 (mutating trigger).

    O jeito correto é criar 3 triggers:
    – uma before/after each row gravando as linhas afetadas numa nested table de uma package. Vai ser after ou before dependendo do que você quer fazer.
    – uma trigger after statement que coleta da nested table o conjunto de linhas afetadas e faz um loop processando sua lógica (no seu caso updates).
    – uma trigger para inicializar a nested table e limpá-la antes de cada statement.

    No Oracle 11g existe o recurso de compound trigger, onde você faz tudo numa trigger composta, que pode possuir todos os momentos (before/after, for each row/statement). A lógica é a mesma acima.

    Aqui tem a cópia do artigo do Tom Kyte solucionando o problema:
    http://glufke.net/oracle/viewtopic.php?t=96

    Seguem alguns artigos relacionados.
    Sobre pragma autonomous transaction:
    http://www.orafaq.com/node/1915
    Sobre erro de mutating trigger:
    http://asktom.oracle.com/pls/asktom/f?p … 9487119866


    Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.4.0
    Connected as fsitja

    SQL> create table tabela_1 (numero number, tipo varchar2(10), campo number(10));

    Table created

    SQL> create table tabela_2 (numero number(10), tipo varchar2(10));

    Table created

    SQL>
    SQL> CREATE OR REPLACE PACKAGE pack_estado_tab_1 IS
    2 type t_nt_tabela_1 is table of tabela_1%rowtype;
    3 nt_tab_1 t_nt_tabela_1 := t_nt_tabela_1(null);
    4 END;
    5 /

    Package created

    SQL>
    SQL> CREATE OR REPLACE TRIGGER tg_tab_1_ai_r
    2 AFTER INSERT ON tabela_1
    3 FOR EACH ROW
    4 DECLARE
    5 v_rec_tab_1 tabela_1%rowtype;
    6 BEGIN
    7 pack_estado_tab_1.nt_tab_1.extend;
    8 v_rec_tab_1.numero := :new.numero;
    9 v_rec_tab_1.tipo := :new.tipo;
    10 v_rec_tab_1.campo := :new.campo;
    11 pack_estado_tab_1.nt_tab_1(pack_estado_tab_1.nt_tab_1.last) := v_rec_tab_1;
    12 END;
    13 /

    Trigger created

    SQL>
    SQL> CREATE OR REPLACE TRIGGER tg_tab_1_bi_s
    2 AFTER INSERT ON tabela_1
    3 BEGIN
    4 pack_estado_tab_1.nt_tab_1.delete;
    5 END;
    6 /

    Trigger created

    SQL>
    SQL> CREATE OR REPLACE TRIGGER tg_tab_1_ai_s
    2 AFTER INSERT ON tabela_1
    3 BEGIN
    4 FOR i IN 1 .. pack_estado_tab_1.nt_tab_1.count
    5 LOOP
    6 INSERT INTO tabela_2
    7 (numero, tipo)
    8 VALUES
    9 (pack_estado_tab_1.nt_tab_1(i).numero, pack_estado_tab_1.nt_tab_1(i).tipo);
    10 UPDATE tabela_1
    11 SET campo = 3
    12 WHERE numero = pack_estado_tab_1.nt_tab_1(i).numero;
    13 END LOOP;
    14 END;
    15 /

    Trigger created

    SQL> insert into tabela_1(numero, tipo) values (1, 'A');

    1 row inserted

    SQL> insert into tabela_1(numero, tipo) values (2, 'B');

    1 row inserted

    SQL> insert into tabela_1(numero, tipo) values (2, 'C');

    1 row inserted

    SQL> select * from tabela_1;

    NUMERO TIPO             CAMPO
    

         1 A                    3
         2 B                    3
         2 C                    3
    

    SQL> select * from tabela_2;

     NUMERO TIPO
    

          1 A
          2 B
          2 C
    

    SQL> rollback;

    Rollback complete

    SQL> drop table tabela_1;

    Table dropped

    SQL> drop table tabela_2;

    Table dropped

    SQL> drop package pack_estado_tab_1;

    Package dropped

    SQL>