Por otro lado en este tipo de tablas hay dos tipos de restricciones, las cuales se presentan a continuación:
1. Las instrucciones de un row trigger no pueden ni leer ni modificar una tabla que está mutando.
2. Las instrucciones de un row trigger no pueden cambiar ni la clave primaria, ni claves foráneas, ni atributos únicos de tablas que estén restringiendo. Esta restricción tiene una excepción: un before row trigger disparado por un INSERT de una sola fila de una tabla con una clave foránea, puede modificar cualquier columna de la tabla primaria siempre que no se viole ninguna de las restricciones de integridad referencial.
Los ERRORES por Tablas Mutantes se detectan y se generan en Tiempo de Ejecución y no de Compilación (ORA-4091).
Ejemplo de Tablas Mutantes
A continuación la descripción de el disparador que da lugar a las tablas mutantes.
Este será un disparador que modifique el número de empleados de un departamento (columna Departamentos.Num_Emp) cada vez que sea necesario. Ese número cambia al INSERTAR o BORRAR uno o más empleados, y al MODIFICAR la columna Dpto de la tabla Empleados, para uno o varios empleados. La tabla Departamentos es una tabla de restricción de la tabla Empleados, pero el Disparador es correcto, porque modifica Num_Emp, que no es la clave primaria. Este disparador no puede consultar la tabla Empleados, ya que esa tabla es mutante (por ejemplo, esta instrucción no sería válida: SELECT COUNT(*) INTO T FROM Empleados WHERE Dpto = :new.Dpto;)
CREATE OR REPLACE TRIGGER Cuenta_Empleados 
BEFORE DELETE OR INSERT OR UPDATE OF Dpto ON Empleados 
FOR EACH ROW 
BEGIN 
IF INSERTING THEN 
UPDATE Departamentos SET Num_Emp = Num_Emp+1 
WHERE NumDpto=:new.Dpto; 
ELSIF UPDATING THEN 
UPDATE Departamentos SET Num_Emp = Num_Emp+1 
WHERE NumDpto=:new.Dpto; 
UPDATE Departamentos SET Num_Emp = Num_Emp-1 
WHERE NumDpto=:old.Dpto; 
ELSE 
UPDATE Departamentos SET Num_Emp = Num_Emp-1 
WHERE NumDpto=:old.Dpto; 
END IF; 
END; 
 El disparador anterior Cuenta_Empleados tiene un inconvenientes: modifica el campo Num_Emp aunque este no tenga el valor correcto.
Ejemplo de la solución para las Tablas Mutantes
Ahora bien basándonos en el ejemplo anterior de tablas mutantes, se escribirá la solución basándonos en la creación de dos nuevos disparadores, uno a nivel de fila y el otro a nivel de after, a continuación se escribira:
CREATE OR REPLACE PACKAGE Empleados_Dpto AS 
TYPE T_Dptos IS TABLE OF Empleados.Dpto%TYPE 
INDEX BY BINARY_INTEGER; 
Tabla_Dptos T_Dptos; 
END Empleados_Dpto; 
CREATE OR REPLACE TRIGGER Fila_Cuenta_Empleados 
AFTER DELETE OR INSERT OR UPDATE OF Dpto ON Empleados FOR EACH ROW 
DECLARE Indice BINARY_INTEGER; 
BEGIN 
Indice := Empleados_Dpto.Tabla_Dptos.COUNT + 1; 
IF INSERTING THEN 
Empleados_Dpto.Tabla_Dptos(Indice) := :new.Dpto; 
ELSIF UPDATING THEN 
Empleados_Dpto.Tabla_Dptos(Indice) := :new.Dpto; 
Empleados_Dpto.Tabla_Dptos(Indice+1):= :old.Dpto; 
ELSE Empleados_Dpto.Tabla_Dptos(Indice) := :old.Dpto; 
END IF; 
END Fila_Cuenta_Empleados; 
CREATE OR REPLACE TRIGGER Orden_Cuenta_Empleados 
AFTER DELETE OR INSERT OR UPDATE OF Dpto ON Empleados 
DECLARE Indice BINARY_INTEGER; 
Total Departamentos.Num_Emp%TYPE; 
Departamento Departamentos.NumDpto%TYPE; 
BEGIN 
FOR Indice IN 1..Empleados_Dpto.Tabla_Dptos.COUNT LOOP 
Departamento := Empleados_Dpto.Tabla_Dptos(Indice); 
SELECT COUNT(*) INTO Total FROM Empleados WHERE Dpto = Departamento; 
UPDATE Departamentos SET Num_Emp = Total WHERE NumDpto = Departamento; 
END LOOP; 
Empleados_Dpto.Tabla_Dptos.DELETE; 
END Orden_Cuenta_Empleados;
Exitos!!!!

 
 
 Entradas
Entradas
 
