在 Oracle 中触发更新,发生变异错误
Trigger update in Oracle, mutating error
我有一个简单的 table 收藏夹。
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 table 正在突变。第 6 行出错。
我该如何防止这种情况发生?我已经搜索过,似乎我的更新会改变我的 select 的值,但我不知道如何改变。
我使用的是 Oracle 版本 11g。
出现错误消息,因为您的触发器同时查询 Favorite
table 而 table 内容正在更改(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.:请参阅上面更新和测试的版本。
您可以在触发器中使用物化视图。
我有一个简单的 table 收藏夹。
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 table 正在突变。第 6 行出错。
我该如何防止这种情况发生?我已经搜索过,似乎我的更新会改变我的 select 的值,但我不知道如何改变。
我使用的是 Oracle 版本 11g。
出现错误消息,因为您的触发器同时查询 Favorite
table 而 table 内容正在更改(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.:请参阅上面更新和测试的版本。
您可以在触发器中使用物化视图。