在创建语句级别触发器时,我遇到了SQL / Oracle 10g的问题。我试图用这个触发器实现的是在学生注册时删除一个实用课程。 5.以下是我写的:
CREATE OR REPLACE TRIGGER delete_prac
AFTER UPDATE ON studEnrol
BEGIN
DELETE FROM pracList
WHERE Practical IN (
SELECT Practical
FROM studEnrol
GROUP BY Practical
HAVING COUNT(Practical) < 5);
END delete_prac;
我得到的错误是:
ORA-04091: pracList table is mutating, trigger/function may not see it
我调查了这个错误,并且出现的建议是包含:new和:old关键字,但我不知道我会怎么做。
感谢任何帮助!
感谢。
编辑:忘了添加哪个表变异,它是pracList表 EDIT2:将其更改为语句级别触发器,并且使用pracList
仍然会发生变异表答案 0 :(得分:2)
这可能发生在Florin Ghita的建议中,因为你在praclist
上有一个触发器。当您更新studenrol
时,请尝试从praclist
删除。此行为会触发另一个触发器,从而导致您的问题。引发此错误是为了提供数据的读取一致视图。由于Tom Kyte says此错误可能表示您的架构或逻辑存在缺陷,您应该重新考虑其中一个或两个。
此外,一般来说,在触发器中进行的全表扫描就是一个坏主意 TM 。根据表格的大小,您最终可能会在studlist
的每次更新上花费1秒或2小时,这远非最佳状态。
如果不知道您的架构或praclist
上的触发器确实很难确定,但在您的情况下,似乎有一个“out”。完全放下这个触发器;没有必要。
在praclist
上创建materialized view,为您提供所需的数据。无论如何,只要有一个视图可以使这里的信息始终保持最新,不断删除和插入值praclist
是没有意义的。以下查询应该这样做:
select p.*
from praclist p
join ( select practical
from studenrol
group by practical
having count(*) >= 5 ) s
on p.practical = s.practical
顺便提一下,如果注册的学生人数突然变得足够实际,那么您当前的触发器不允许插入praclist
。物化视图处理此问题以及变异表错误。
答案 1 :(得分:1)
删除FOR EACH ROW
然后你的触发器只会在更新行后运行一次,并且表格不会发生变异。