oracle触发器出错
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle触发器出错相关的知识,希望对你有一定的参考价值。
写了一个触发器,但是老是出错,希望各位给指点一下,小弟还是初学者,所以希望能说得浅显一点些
create or replace trigger af_del_jg
after delete on jg_place01
for each row
declare
v_k number(30) := 0;
begin
select count(jg_u) into v_k from jg_place01 where cabinet = :old.cabinet and area = :old.area;
if( v_k = 0 )then
delete from tab_power01 where area=:old.area and cabinet = :old.cabinet;
end if;
end af_del_jg;
提示信息是:
ORA-04091:表 test. jg_place01 发生了变化,触发器/函数不能读它
ORA-06512:在"test.af_del_jg",line5
ORA-04088:触发器:test.af_del_jg在执行过程中出错
我们详细分析下:
1 测试表
[TEST2@orcl#10-4月 -11] SQL>select * from t2;
A B C
---------- ---------- ----------
1 2 2
1 2 3
4 5 6
2 测试的触发器 (抄你的 改了表名 列名 而且加入输出语句用以判断问题出在哪里)
create or replace trigger af_del_t2
after delete on t2
for each row
declare
v_k number(30) := 0;
begin
dbms_output.put_line(\'v_k1=\'||v_k);
dbms_output.put_line(\'old.a=\'||:old.a||\' old.b=\'||:old.b);
select count(c) into v_k from t2 where a = :old.a and b = :old.b;
dbms_output.put_line(\'v_k2=\'||v_k);
if( v_k = 0 ) then
dbms_output.put_line(\'v_k2=\'||v_k);
delete from t2 where b =:old.b and a = :old.a;
commit;
end if;
end af_del_t2;
/
3 测试
[TEST2@orcl#10-4月 -11] SQL>delete from t2 where c=6;
v_k1=0
old.a=4 old.b=5
delete from t2 where c=6
*
第 1 行出现错误:
ORA-04091: 表 TEST2.T2 发生了变化, 触发器/函数不能读它
ORA-06512: 在 "TEST2.AF_DEL_T2", line 6
ORA-04088: 触发器 \'TEST2.AF_DEL_T2\' 执行过程中出错
4 由此可得出错误出在
select count(c) into v_k from t2 where a = :old.a and b = :old.b; 这一行中
5 错误分析
从上面的测试以及错误信息可以得出:
你先对表进行了delete 操作。但是没有commit;
这个时候表就处于锁定状态,导致你从这个表select的时候报错。
6 继续分析
[TEST2@orcl#10-4月 -11] SQL>drop trigger af_del_t2;
触发器已删除。
[TEST2@orcl#10-4月 -11] SQL>select * from t2;
A B C
---------- ---------- ----------
1 2 2
1 2 3
4 5 6
[TEST2@orcl#10-4月 -11] SQL>delete from t2 where c=6;
已删除 1 行。
[TEST2@orcl#10-4月 -11] SQL>select count(*) from t2;
COUNT(*)
----------
2
删除触发器,再删除记录(没有commit)。再select这个表却可以。
个人推论:1 在没有触发器的情况下,我上面的删除和查询属于同一个事务,故没有问题
2 有触发器的情况下,删除和触发器里的查询属于2个不同的事务,导致锁表的问题,出现错误。
6 解决
既然是事务的问题,那么就从这方面下手。刚百度了下,关键词ORA-04091 发现一个概念“自治事务” 修改如下:
create or replace trigger af_del_t2
after delete on t2
for each row
declare
pragma autonomous_transaction;
v_k number(30) := 0;
begin
dbms_output.put_line(\'v_k1=\'||v_k);
dbms_output.put_line(\'old.a=\'||:old.a||\' old.b=\'||:old.b);
select count(c) into v_k from t2 where a = :old.a and b = :old.b;
dbms_output.put_line(\'v_k2=\'||v_k);
if( v_k = 0 ) then
dbms_output.put_line(\'v_k3=\'||v_k);
delete from t2 where b =:old.b and a = :old.a;
commit;
end if;
end af_del_t2;
/
其中加入一个自治事务;
[TEST2@orcl#10-4月 -11] SQL>select * from t2;
A B C
---------- ---------- ----------
1 2 2
1 2 3
4 5 6
[TEST2@orcl#10-4月 -11] SQL>delete from t2 where c=2;
v_k1=0
old.a=1 old.b=2
v_k2=2
已删除 1 行。
[TEST2@orcl#10-4月 -11] SQL>select * from t2;
A B C
---------- ---------- ----------
1 2 3
4 5 6
到这里不能select的问题解决了。
其实你这个触发器还有一些其它问题,你再多看看,检查下你的业务逻辑。等你自己发现了问题 我再帮你解答。追问
那个....其实您的触发器写错了,在触发器里面查询和删除并不是同一张表来着,这个触发器是在对一张表执行删除操作之后对另一张表进行判断,满足条件的话就执行删除
追答恩 错了没关系
你的原本写的触发器问题不是出在delete from tab_power01 where area=:old.area and cabinet = :old.cabinet;
上。 所以这句话没关系。
你好,请问你这个问题解决了没?
当我调用触发器更新 STUDENT 表中的总数时,Oracle 中的 SQL 出错
【中文标题】当我调用触发器更新 STUDENT 表中的总数时,Oracle 中的 SQL 出错【英文标题】:got error in SQL in my oracle when i call my trigger to update total in my STUDENT table 【发布时间】:2021-05-11 06:01:20 【问题描述】:我必须调用一个触发器,在插入查询后更新总计和百分比字段 这是代码
create table bhrugus1 (
student_name varchar2(100),
dbms number,
dsa number,
mco number,
total number,
percentage number,
roll_no number primary key
);
CREATE OR REPLACE TRIGGER trial1
AFTER INSERT on bhrugus1
REFERENCING new AS new
FOR EACH ROW
BEGIN
:new.total := :new.dbms + :new.dsa + :new.mco;
:new.percentage := (:new.dbms + :new.dsa + :new.mco) / 3 ;
END;
insert into bhrugus1 values ('bhrugu',90,90,90,1,1,2);
SELECT * from bhrugus1;
表格和运行触发器时出现错误
the new error
【问题讨论】:
看起来像这样***.com/questions/47584800/…。将您的“bhrugu”更改为“bhrugu” 我更新了我的代码得到了新的错误@Craig As documented in the manual PL/SQL 中的赋值运算符是:=
我现在更新它说“无法更改此触发器类型的新值”
触发器必须在插入之前而不是在插入之后。
【参考方案1】:
请修改您的触发器:
CREATE OR REPLACE TRIGGER trial1
before INSERT on bhrugus1
REFERENCING new AS new
FOR EACH ROW
BEGIN
:new.total := :new.dbms + :new.dsa + :new.mco;
:new.percentage := (:new.dbms + :new.dsa + :new.mco) / 3 ;
END;
您不应在触发器中运行更新语句,请使用 :new... 而不是更新。
另一个重要的事情是:
before insert
【讨论】:
我修改了答案:触发器在insert之前,赋值运算符为:=,正如a_horse_with_no_name所说。 它解决了错误,我之前和之前都这样做过【参考方案2】:您缺少一个组件,当有人更新任何或所有 dbms、dsa、mco 时会发生什么。没有更新触发器来重新计算总数或百分比。您当然可以在触发器上包含“或更新”。然而,更好的方法是将它们定义为虚拟列。
create table bhrugus1 (
student_name varchar2(100),
dbms number,
dsa number,
mco number,
total number generated always as (dbms+dsa+mco) virtual,
percentage number generated always as ((dbms+dsa+mco)/3) virtual,
roll_no number primary key
);
总和百分比(不好的名字是平均值 - 但这是另一个问题)将始终正确计算。并放下不再需要的触发器。
【讨论】:
以上是关于oracle触发器出错的主要内容,如果未能解决你的问题,请参考以下文章
当我调用触发器更新 STUDENT 表中的总数时,Oracle 中的 SQL 出错
在oracle中插入表B后创建触发器以将新行添加到表A中时出错