Apenas para esclarecer, a exceção da tabela mutante é lançada porque você está tentando ler as
rooms
table em sua função, não porque você está tentando ler as properties
tabela. Como você tem um acionador em nível de linha em rooms
, isso significa que as rooms
table está no meio de uma alteração quando o gatilho em nível de linha está sendo acionado e pode estar em um estado inconsistente. O Oracle impede que você consulte as rooms
tabela nessa situação porque os resultados não são necessariamente determinísticos ou reprodutíveis. Se você criou um gatilho de nível de instrução (removendo o
FOR EACH ROW
) e colocar sua lógica lá, você não encontrará mais uma exceção de tabela mutante porque as rooms
tabela não estaria mais em um estado inconsistente. Um gatilho de nível de instrução, no entanto, não é capaz de ver quais linhas foram modificadas. Isso significaria que você precisaria examinar todas as propriedades para ver quais valores de status devem ser ajustados. Isso não vai ser particularmente eficiente. Ao custo de complexidade adicional, você pode melhorar o desempenho capturando quais propriedades foram alteradas em um gatilho de nível de linha e, em seguida, referindo-se a elas em um gatilho de nível de instrução. Isso geralmente requer três gatilhos e um pacote, o que obviamente aumenta o número de peças móveis substancialmente (se você estiver no 11.2, você pode usar um gatilho composto com três gatilhos de componentes que simplifica um pouco as coisas, eliminando a necessidade de usar o pacote) . Isso seria 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;