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;