我有一个名为收藏夹的简单表。
Favorites
| username | type_of_movie | like_or_dislike |
数据如下所示:
AAA, Action, Like
AAA, Romance, Dislike
...
我制作了一个触发器来计算最喜欢的类型并阻止用户喜欢所有类型。
CREATE OR REPLACE TRIGGER trgLike
BEFORE INSERT OR UPDATE ON Favorite
FOR EACH ROW
DECLARE
count number;
BEGIN
SELECT
COUNT(username) INTO count
FROM
Favorite
WHERE
username= :NEW.username AND like_or_dislike = 'Like';
IF (count = 3) THEN
RAISE_APPLICATION_ERROR(-20000,'Too much liking');
END IF;
END;
/
我希望用户能够喜欢3种类型的电影。
插入触发器工作得很好但是当我尝试更新某些东西而不喜欢时,我得到并且错误ORA-04091表处于变异状态。第6行出错。
我该怎样防止这种情况?我搜索过,似乎我的更新会改变我的选择值,但我不知道如何。
我使用的是Oracle 11g版。
答案 0 :(得分:3)
出现错误消息,因为您的触发器在表内容发生变化时同时查询Favorite
表(UPDATE
或INSERT
)。
要解决此问题,您需要三个触发器和一个小包:
CREATE OR REPLACE PACKAGE state_pkg AS
type ridArray IS TABLE OF rowid INDEX BY binary_integer;
newRows ridArray;
empty ridArray;
END;
/
CREATE OR REPLACE TRIGGER trgLike_clear_table
BEFORE INSERT OR UPDATE ON Favorite
BEGIN
state_pkg.newRows := state_pkg.empty;
END;
/
CREATE OR REPLACE TRIGGER trgLike_capture_affected_rows
AFTER INSERT OR UPDATE ON Favorite FOR EACH ROW
BEGIN
state_pkg.newRows(state_pkg.newRows.count +1) := :new.rowid;
END;
/
CREATE OR REPLACE TRIGGER trgLike_do_work
AFTER INSERT OR UPDATE ON Favorite
DECLARE
likes NUMBER;
BEGIN
FOR i IN 1..state_pkg.newRows.count LOOP
SELECT COUNT(*) INTO likes
FROM Favorite
WHERE username = (SELECT username FROM Favorite WHERE rowid = state_pkg.newRows(i))
AND like_or_dislike = 'Like';
IF (likes = 3) THEN
RAISE_APPLICATION_ERROR(-20000, 'Too much liking');
END IF;
END LOOP;
END;
/
在AskTom上有一个nice article。
p.s。 :请参阅上面的更新和测试版本。
答案 1 :(得分:0)
您可以在触发器中使用物化视图。