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;
上。 所以这句话没关系。

你好,请问你这个问题解决了没?

参考技术A 这个触发器是在删除的时候触发,但是你在这个触发器中又有删除动作,这样会不会有个无线循环在裏面了,使得运行出错。 参考技术B 该先明白你的思路是什么。你的 jg_place01 表的列在删除成功的之后才触发删除,你都删除了,在删除肯定抱错。

当我调用触发器更新 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中时出错

Oracle 语法错误触发器

oracle用imp导入用户数据时,提示表或视图不存在

使用 Apache Ant 而不是 Oracle SQL Developer 执行 SQL 时出错

PL/SQL Oracle 错误处理