明確にするために、rooms
から読み取ろうとしているため、変更テーブルの例外がスローされます。 properties
から読み取ろうとしているためではなく、関数内のテーブル テーブル。 rooms
に行レベルのトリガーがあるため 、つまり、rooms
行レベルのトリガーが起動しているときにテーブルが変更の途中であり、一貫性のない状態になっている可能性があります。 Oracleは、rooms
にクエリを実行できないようにします。 結果は必ずしも決定論的または再現可能であるとは限らないため、その状況での表。
ステートメントレベルのトリガーを作成した場合(FOR EACH ROW
を削除 )そしてそこにロジックを配置すると、rooms
が原因で、変更テーブルの例外が発生しなくなります。 テーブルが不整合な状態になることはなくなりました。ただし、ステートメントレベルのトリガーは、どの行が変更されたかを確認できません。つまり、どのステータス値を調整する必要があるかを確認するには、すべてのプロパティを調べる必要があります。これは特に効率的ではありません。
さらに複雑になりますが、行レベルのトリガーで変更されたプロパティをキャプチャし、それをステートメントレベルのトリガーで参照することで、パフォーマンスを向上させることができます。これには通常、3つのトリガーとパッケージが必要です。これにより、移動するピースの数が明らかに大幅に増加します(11.2を使用している場合は、パッケージを使用する必要がないため、3つのコンポーネントトリガーを備えた複合トリガーを使用できます)。 。それは次のようになります
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;