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.