Oracle编写Watch表插入触发器报PLS-00103 SELECT符号错误咨询
错误原因
你遇到的报错主要由三类问题导致:
- 伪记录引用语法错误:Oracle触发器中引用
NEW/OLD伪记录必须加前缀冒号,你代码中写的new.movie_ID不符合语法要求,解析器无法识别该标识符,直接触发PLS-00103符号错误。 - 字段名拼写错误:Movie表的平均评分字段为
avg_rating,你代码中误写为ava_rating,即使语法问题修复后执行也会报字段不存在错误。 - 突变表限制问题:Oracle行级触发器默认不允许在触发事务中读取正在触发触发器的表(即本例中的Watch表),你在UPDATE的子查询中直接查询Watch表,就算语法修复后也会报
ORA-04091突变表错误。
解决方法
提供两种可正常运行的实现方案:
方案1:语句级触发器(兼容所有Oracle版本)
放弃逐行触发逻辑,每次插入操作完成后统一更新评分,规避突变表限制:
CREATE OR REPLACE TRIGGER trig1 AFTER INSERT ON Watch BEGIN UPDATE Movie m SET avg_rating = ( SELECT AVG(rating) FROM Watch w WHERE w.movie_ID = m.movie_ID ) WHERE EXISTS ( SELECT 1 FROM Watch w WHERE w.movie_ID = m.movie_ID ); END; /
方案2:复合触发器(Oracle 11g及以上版本支持,性能更优)
暂存本次插入涉及的电影ID,仅更新对应电影的评分,避免全表扫描:
CREATE OR REPLACE TRIGGER trig1 FOR INSERT ON Watch COMPOUND TRIGGER TYPE t_movie_ids IS TABLE OF Watch.movie_ID%TYPE INDEX BY PLS_INTEGER; v_movie_ids t_movie_ids; BEFORE EACH ROW IS BEGIN IF :NEW.movie_ID IS NOT NULL THEN v_movie_ids(:NEW.movie_ID) := :NEW.movie_ID; END IF; END BEFORE EACH ROW; AFTER STATEMENT IS BEGIN FOR i IN 1..v_movie_ids.COUNT LOOP UPDATE Movie SET avg_rating = ( SELECT AVG(rating) FROM Watch WHERE movie_ID = v_movie_ids(i) ) WHERE movie_ID = v_movie_ids(i); END LOOP; END AFTER STATEMENT; END trig1; /
内容的提问来源于stack exchange,提问作者Long Huynh
相关产品推荐
相关产品推荐

