Oracle
 sql >> Database >  >> RDS >> Oracle

Oracle DBMS - Leggere una tabella prima di elaborare l'aggiornamento in un trigger AFTER - tabella mutante

Giusto per chiarire, viene generata l'eccezione della tabella mutante perché stai cercando di leggere dalle rooms table nella tua funzione, non perché stai cercando di leggere dalle properties tavolo. Poiché hai un attivatore a livello di riga su rooms , ciò significa che le rooms la tabella è nel mezzo di una modifica quando il trigger a livello di riga si attiva e potrebbe trovarsi in uno stato incoerente. Oracle ti impedisce di interrogare le rooms tabella in quella situazione perché i risultati non sono necessariamente deterministici o riproducibili.

Se hai creato un trigger a livello di istruzione (rimuovendo il FOR EACH ROW ) e metti lì la tua logica, non incontrerai più un'eccezione di tabella mutante perché le rooms la tabella non sarebbe più in uno stato incoerente. Un trigger a livello di istruzione, tuttavia, non è in grado di vedere quali righe sono state modificate. Ciò significherebbe che dovresti esaminare tutte le proprietà per vedere quali valori di stato devono essere regolati. Non sarà particolarmente efficiente.

A costo di ulteriore complessità, è possibile migliorare le prestazioni acquisendo quali proprietà sono state modificate in un trigger a livello di riga e quindi facendo riferimento a quelle in un trigger a livello di istruzione. Ciò richiede generalmente tre trigger e un pacchetto, che ovviamente aumenta notevolmente il numero di pezzi in movimento (se sei su 11.2, puoi utilizzare un trigger composto con trigger a tre componenti che semplifica un po' le cose eliminando la necessità di utilizzare il pacchetto) . Sembrerebbe qualcosa di simile a

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;