Chỉ cần làm rõ, ngoại lệ bảng đột biến được ném ra vì bạn đang cố đọc từ rooms
trong hàm của bạn, không phải vì bạn đang cố đọc từ các thuộc tính properties
bàn. Vì bạn có trình kích hoạt cấp hàng trên rooms
, điều đó có nghĩa là rooms
bảng đang ở giữa sự thay đổi khi trình kích hoạt cấp hàng đang kích hoạt và nó có thể ở trạng thái không nhất quán. Oracle ngăn bạn truy vấn rooms
trong tình huống đó vì kết quả không nhất thiết phải xác định hoặc có thể lặp lại.
Nếu bạn đã tạo trình kích hoạt cấp câu lệnh (xóa FOR EACH ROW
) và đặt logic của bạn ở đó, bạn sẽ không còn gặp phải ngoại lệ bảng thay đổi vì rooms
bảng sẽ không còn ở trạng thái không nhất quán. Tuy nhiên, trình kích hoạt cấp câu lệnh không thể xem (các) hàng nào đã được sửa đổi. Điều đó có nghĩa là bạn cần phải xem xét tất cả các thuộc tính để xem giá trị trạng thái nào nên được điều chỉnh. Điều đó sẽ không đặc biệt hiệu quả.
Với chi phí phức tạp hơn, bạn có thể cải thiện hiệu suất bằng cách nắm bắt các thuộc tính nào đã thay đổi trong trình kích hoạt cấp hàng và sau đó tham chiếu đến thuộc tính đó trong trình kích hoạt cấp câu lệnh. Điều đó thường yêu cầu ba trình kích hoạt và một gói, điều này rõ ràng làm tăng đáng kể số lượng các mảnh chuyển động (nếu bạn đang ở trên 11.2, bạn có thể sử dụng trình kích hoạt kết hợp với ba trình kích hoạt thành phần giúp đơn giản hóa mọi thứ một chút bằng cách loại bỏ nhu cầu sử dụng gói) . Nó sẽ trông giống như
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;