在Oracle中触发更新,改变错误

时间:2015-04-11 19:36:43

标签: oracle plsql

我有一个名为收藏夹的简单表。

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版。

2 个答案:

答案 0 :(得分:3)

出现错误消息,因为您的触发器在表内容发生变化时同时查询Favorite表(UPDATEINSERT)。

要解决此问题,您需要三个触发器和一个小包:

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)

您可以在触发器中使用物化视图。