电影评级触发器
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 中,专门针对此类作业,并且是此类作业的先决条件)数据设计的基础知识,包括但不限于数据规范化、第一范式、第二范式和第三范式(查找它们)。
我想创建一个对电影进行平均评分的触发器。我试图创建一个触发器,但是当我添加新的评级数据时,触发器出现错误
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 中,专门针对此类作业,并且是此类作业的先决条件)数据设计的基础知识,包括但不限于数据规范化、第一范式、第二范式和第三范式(查找它们)。