Само за пояснение, изключението на променящата се таблица се хвърля, защото се опитвате да четете от rooms
таблица във вашата функция, а не защото се опитвате да четете от properties
маса. Тъй като имате тригер на ниво ред на rooms
, това означава, че rooms
таблицата е в средата на промяна, когато тригерът на ниво ред се задейства и че може да е в непоследователно състояние. Oracle ви пречи да правите запитвания към rooms
таблица в тази ситуация, защото резултатите не са непременно детерминистични или възпроизводими.
Ако сте създали тригер на ниво изявление (премахване на FOR EACH ROW
) и поставете логиката си там, вече няма да срещнете изключение на променяща се таблица, защото rooms
таблицата вече няма да бъде в непоследователно състояние. Тригерът на ниво изявление обаче не може да види кой ред(ове) е бил променен. Това би означавало, че ще трябва да разгледате всички свойства, за да видите кои стойности на състоянието трябва да бъдат коригирани. Това няма да е особено ефективно.
С цената на допълнителна сложност можете да подобрите производителността, като заснемете кои свойства са променени в тригер на ниво ред и след това се позовавате на това в тригер на ниво израз. Това обикновено изисква три тригера и пакет, което очевидно значително увеличава броя на движещите се части (ако сте на 11.2, можете да използвате комбиниран тригер с три компонентни тригера, което малко опростява нещата, като елиминира необходимостта от използване на пакета) . Това би изглеждало нещо като
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;