El error del disparador de mutación de Oracle ocurre cuando un disparador hace referencia a la tabla que posee el disparador, lo que resulta en el mensaje "ORA-04091:el nombre de la tabla está mutando, es posible que el disparador/la función no lo vean".
Echemos un vistazo a las soluciones alternativas existentes.
El primero, a través del paquete, es antiguo y parece ser efectivo, sin embargo, lleva mucho tiempo prepararlo y ejecutarlo. El segundo es simple y se realiza con disparadores compuestos.
create table turtles as select 'Splinter' name, 'Rat' essence from dual union all select 'Leonardo', 'Painter' from dual union all select 'Rafael', 'Painter' from dual union all select 'Michelangelo', 'Painter' from dual union all select 'Donatello', 'Painter' from dual;

Cuando Splinter mute de rata a sensei, los pintores tendrán que convertirse automáticamente en ninjas. Este activador parece adecuado:
create or replace trigger tr_turtles_bue
before update of essence
on turtles
for each row
when (
new.name = 'Splinter' and old.essence = 'Rat' and new.essence = 'Sensei'
)
begin
update turtles
set essence = 'Ninja'
where essence = 'Painter';
end; Sin embargo, al actualizar el registro:
update turtles set essence = 'Sensei' where name = 'Splinter'
Se produce el siguiente error:
ORA-04091:la tabla SCOTT.TURTLES está mutando, es posible que el activador o la función no lo vean
Eliminemos este disparador:
drop trigger tr_turtles_bue;
El método 1: Usando el paquete y el activador de nivel de instrucción.
create or replace package pkg_around_mutation
is
bUpdPainters boolean;
procedure update_painters;
end pkg_around_mutation;
/
create or replace package body pkg_around_mutation
is
procedure update_painters
is
begin
if bUpdPainters then
bUpdPainters := false;
update turtles
set essence = 'Ninja'
where essence = 'Painter';
end if;
end;
end pkg_around_mutation;
/
create or replace trigger tr_turtles_bue
before update of essence
on turtles
for each row
when (
new.name = 'Splinter' and old.essence = 'Rat' and new.essence = 'Sensei'
)
begin
pkg_around_mutation.bUpdPainters := true;
end tr_turtles_bue;
/
create or replace trigger tr_turtles_bu
after update
on turtles
begin
pkg_around_mutation.update_painters;
end tr_turtles_bu;
/ El método 2: Uso de activadores DML compuestos (disponibles a partir de Oracle 11g).
create or replace trigger tr_turtles_ue
for update of essence
on turtles
compound trigger
bUpdPainters boolean;
before each row is
begin
if :new.name = 'Splinter' and :old.essence = 'Rat' and :new.essence = 'Sensei' then
bUpdPainters := true;
end if;
end before each row;
after statement is
begin
if bUpdPainters then
update Turtles
set essence = 'Ninja'
where essence = 'Painter';
end if;
end after statement;
end tr_turtles_ue; Intentemos lo siguiente:
update turtles set essence = 'Sensei' where name = 'Splinter'

Incluso si se enfrenta a un caso de mutación más complejo, puede utilizar la idea mencionada anteriormente como solución alternativa. En el disparador de nivel de instrucción, a diferencia del disparador de nivel de fila, no se produce ninguna mutación. Puede usar variables (etiquetas, pestillos, tablas PL SQL) en un paquete adicional o variables que son globales para todas las secciones del activador compuesto, lo cual es preferible a partir de la versión Oracle 11g. Entonces, ahora también sabes kung fu.
Puede encontrar información adicional sobre activadores en:Activadores DML compuestos
Siéntase libre de agregar cualquier comentario.