电影评级触发器

Movies rating trigger

我想创建一个对电影进行平均评分的触发器。我试图创建一个触发器,但是当我添加新的评级数据时,触发器出现错误

ORA-04091: table RATING is mutating, trigger/function may not see it

我已经搜索了该问题的解决方案,因为在触发器中使用了 select。但是我不知道应该怎么修改我的代码,请问有什么解决办法吗?

CREATE OR REPLACE TRIGGER AvgRate_trig
AFTER INSERT ON Rating
FOR EACH ROW
BEGIN
    UPDATE TB_MOVIES 
    SET AvgRating = (SELECT AVG(RATE) FROM RATING 
                     WHERE tb_movies.movieid = rating.movieid)
    WHERE movieid = new.movieid;
END

您可以更喜欢使用 语句级触发器 而不是 行级触发器 从删除行 FOR EACH ROW 开始,这样为了获得新的触发器主体,例如

CREATE OR REPLACE TRIGGER AvgRate_trig
  AFTER INSERT ON rating
BEGIN
  UPDATE tb_movies t
     SET AvgRating =
         (SELECT AVG(rate)
            FROM rating r
           WHERE t.movieid = r.movieid)
   WHERE movieid IN 
         (SELECT movieid
            FROM rating
           GROUP BY movieid)   
END;
/

这样你就不会得到 tabe 变异错误。

为了解决有缺陷的设计,鉴于我最初的评论似乎没有被 OP 理解,这里有一个演示正是我在说什么。数据设计的一个基本规则是,你不计算和存储一个可以在 运行 时间计算的值。在这个特定的应用程序中,这意味着您不会尝试不断更新和存储多个电影评级的平均值。相反,在需要时计算它。

SQL> show user
USER is "SCOTT"
SQL> -- -------- create the tables
SQL> create table movies
  2     (    movie_id number not null enable,
  3          movie_title varchar2(30) not null enable,
  4           constraint movies_pk primary key (movie_id)
  5    )
  6  ;

Table created.

SQL> --
SQL> create table ratings
  2     (    rating_id number not null enable,
  3          movie_id number not null enable,
  4          rating_source varchar2(30) not null enable,
  5          movie_rating number not null enable,
  6           constraint ratings_pk primary key (rating_id, movie_id),
  7           constraint ratings_chk1 check (movie_rating in (1,2,3,4,5)) enable,
  8           constraint ratings_fk1 foreign key (movie_id)
  9            references scott.movies (movie_id) on delete cascade enable
 10     )
 11  ;

Table created.

SQL> -- -------- load tables
SQL> insert into movies values (1,'To Kill A Mockingbird');

1 row created.

SQL> insert into ratings values (1,1,'Rotten Tomatoes',2);

1 row created.

SQL> insert into ratings values (2,1,'ImDB',2);

1 row created.

SQL> insert into ratings values (3,1,'Amazon User',3);

1 row created.

SQL> --
SQL> insert into movies values (2,'Saving Private Ryan');

1 row created.

SQL> insert into ratings values (4,2,'Rotten Tomatoes',4);

1 row created.

SQL> insert into ratings values (5,2,'ImDB',5);

1 row created.

SQL> insert into ratings values (6,2,'Amazon User',5);

1 row created.

SQL>
SQL> -- -------- Do the query
SQL> select * from movies;

  MOVIE_ID MOVIE_TITLE
---------- ------------------------------
         1 To Kill A Mockingbird
         2 Saving Private Ryan

2 rows selected.

SQL> select * from ratings;

 RATING_ID   MOVIE_ID RATING_SOURCE                  MOVIE_RATING
---------- ---------- ------------------------------ ------------
         1          1 Rotten Tomatoes                           2
         2          1 ImDB                                      2
         3          1 Amazon User                               3
         4          2 Rotten Tomatoes                           4
         5          2 ImDB                                      5
         6          2 Amazon User                               5

6 rows selected.

SQL> select m.movie_title,
  2         avg(r.movie_rating)
  3  from movies m
  4    join ratings r on m.movie_id = r.movie_id
  5  group by m.movie_title
  6  order by m.movie_title
  7  ;

MOVIE_TITLE                    AVG(R.MOVIE_RATING)
------------------------------ -------------------
Saving Private Ryan                     4.66666667
To Kill A Mockingbird                   2.33333333

2 rows selected.

SQL> -- -------- clean up
SQL> drop table ratings purge;

Table dropped.

SQL> drop table movies purge;

Table dropped.

也就是说,原始问题(如何编写触发器)具有作业问题的所有指定。现在,如果作业是非常具体地编写这样一个触发器,那么人们希望目的是教授一些编码技术。这不是我们第一次看到基于非常有缺陷的设计的特定家庭作业,而且问题所暗示的设计非常有缺陷。当我看到这样的时候,我严重质疑导师的资格,在面对基本数据设计原则的情况下进行作业。他们应该已经涵盖了(实际上,在 class 中,专门针对此类作业,并且是此类作业的先决条件)数据设计的基础知识,包括但不限于数据规范化、第一范式、第二范式和第三范式(查找它们)。