Solo para aclarar, la excepción de la tabla mutante se lanza porque está tratando de leer desde las rooms
tabla en su función, no porque esté tratando de leer de las properties
mesa. Dado que tiene un activador de nivel de fila en rooms
, eso significa que las rooms
la tabla está en medio de un cambio cuando el activador de nivel de fila se está activando y que puede estar en un estado incoherente. Oracle le impide consultar las rooms
tabla en esa situación porque los resultados no son necesariamente deterministas o reproducibles.
Si creó un disparador a nivel de declaración (eliminando el FOR EACH ROW
) y coloque su lógica allí, ya no encontrará una excepción de tabla mutante porque las rooms
la tabla ya no estaría en un estado inconsistente. Sin embargo, un disparador a nivel de instrucción no puede ver qué fila(s) se modificaron. Eso significaría que necesitaría mirar todas las propiedades para ver qué valores de estado deben ajustarse. Eso no va a ser particularmente eficiente.
A costa de una complejidad adicional, puede mejorar el rendimiento capturando qué propiedades cambiaron en un disparador de nivel de fila y luego haciendo referencia a eso en un disparador de nivel de declaración. Eso generalmente requiere tres disparadores y un paquete, lo que obviamente aumenta sustancialmente la cantidad de piezas móviles (si está en 11.2, puede usar un disparador compuesto con disparadores de tres componentes que simplifica un poco las cosas al eliminar la necesidad de usar el paquete) . Eso sería algo como
CREATE OR REPLACE PACKAGE trigger_collections
AS
TYPE modified_property_tbl IS TABLE OF properties.property_id%type;
g_modified_properties modified_property_tbl;
END;
-- Initialize the collection in a before statement trigger just in case
-- there were values there from a prior run
CREATE OR REPLACE TRIGGER trg_initialize_mod_prop_coll
BEFORE INSERT OR UPDATE ON rooms
BEGIN
trigger_collections.g_modified_properties := trigger_collections.modified_property_tbl();
END;
-- Put the property_id of the modified row in the collection
CREATE OR REPLACE TRIGGER trg_populate_mod_prop_coll
AFTER INSERT OR UPDATE ON rooms
FOR EACH ROW
BEGIN
trigger_collections.g_modified_properties.extend();
trigger_collections.g_modified_properties( trigger_collections.g_modified_properties.count + 1 ) := :new.property_id;
END;
CREATE OR REPLACE TRIGGER trg_process_mod_prop_coll
AFTER INSERT OR UPDATE ON rooms
BEGIN
FOR p IN 1 .. trigger_collections.g_modified_properties.count
LOOP
IF prop_vacancy_query( trigger_collections.g_modified_properties(i) ) = 0
THEN
...
END;