sql >> Base de Datos >  >> RDS >> Oracle

Oracle DBMS:lea una tabla antes de procesarla Actualización en un disparador DESPUÉS:tabla mutante

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;