我有以下错误:
ORA-04091:表SYSTEM.ORDINE正在变异,触发器/函数可能不变 看到它
在此触发器上PL / SQL:
create or replace trigger T_Ordine
after insert on Ordine
for each row
DECLARE
conta number := 0;
t_o exception;
BEGIN
select count(*) into conta
from Cliente join Ordine on Cliente.ID_Cliente = Ordine.ID_CLiente
where Cliente.C_CF_Rivenditore <> Ordine.CF_Rivenditore;
if conta > 0 then
raise t_o;
end if;
EXCEPTION
when t_o then
raise_application_error(-20002,'Un rivenditore non puo ricevere ordini da un cliente non suo');
end;
/
我认为在表Ordine
的联接中修改表Cliente
导致错误。
答案 0 :(得分:2)
你的触发器有点奇怪。
您已将其声明为for each row
,但您从未使用:new
来访问任何已插入的值。
据我所知,有两种方法可以修复你的触发器:
使触发器成为语句级触发器,以便在插入ordine
表后运行一次,无论插入多少行。为此,只需删除行for each row
。
调整触发器以仅检查插入的顺序,而不是检查表中的每个顺序。为此,请使用以下内容替换用于查找conta
的SQL查询:
select count(*) into conta
from Cliente
where Cliente.ID_Cliente = :new.ID_CLiente
and Cliente.C_CF_Rivenditore <> :new.CF_Rivenditore;
请注意,我们不再查询Ordine
表 - 刚刚插入的行的详细信息可用:new.column_name
。这可以解决ORA-04091
错误。
我会推荐第二种方法。您用于查找conta
的查询当前搜索整个Ordine
表,并且随着您的应用程序获得越来越多的订单,当查询搜索越来越多的数据时,此触发器会变得越来越慢。此外,您可能不希望您的应用程序拒绝接受任何人的任何订单,如果它发生在系统中某个位置,客户端Rivenditore
没有&#39} ; \ t匹配订单&#39; s Rivenditore
。
顺便说一下,提出异常t_o
,抓住它并引发替代异常并不是很重要。立即提出第二个例外,即:
if conta > 0 then
raise_application_error(-20002,'Un rivenditore non puo ricevere ordini da un cliente non suo');
end if;
答案 1 :(得分:1)
由于我是意大利人,我在理解你要做的事情方面有点优势:
您只是想让卖家不能为每个客户指定的订单插入订单(这是您的错误消息所说的),但您不知道如何使用:new或:old,所以你用这种方式编写了测试(这并不是最好的方法,因为每次插入新订单时你都会重新检查表中的所有订单。)
这是你真正想写的:
create or replace trigger T_Ordine
after insert on Ordine
for each row
DECLARE
rivenditore_del_cliente Cliente.C_CF_Rivenditore%type;
BEGIN
select Cliente.C_CF_Rivenditore
into rivenditore_del_cliente
from Cliente
where Cliente.ID_Cliente = :new.ID_CLiente
if rivenditore_del_cliente <> :new.CF_Rivenditore then
raise raise_application_error(-20002,
'Un rivenditore non puo ricevere ordini da un cliente non suo');
end if;
end;
如果其中一些是真的,可能需要进一步检查上述触发器: