Oracle数据库如何解决ORA-04091触发器/函数不能读它的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle数据库如何解决ORA-04091触发器/函数不能读它的问题相关的知识,希望对你有一定的参考价值。

这是学校给出的作业中的一道题目:
使用create trigger语句创建触发器tri_insert,创建一个insert类型的触发器,要求当用户在student表中插入的班级号为99时,自动将班级号修改为1;
然后编写代码如下:

create or replace trigger tri_insert
after insert on student
for each row
begin
update student set class=1 where class=99;
end tri_insert;

编译是能通过的,但是插入数据的时候就出问题了:
ORA-04091: 表 HR.STUDENT 发生了变化, 触发器/函数不能读它
ORA-06512: 在 "HR.TRI_INSERT", line 5
ORA-04088: 触发器 'HR.TRI_INSERT' 执行过程中出错
去网上找了一下,知道错误的原因是,
trigger 中的执行语句不能读写 它依附的表。
度娘上搜到的很多解决方案例子都是解决select语句问题的,用:new和:old就解决了,
但是针对这个问题,要对student表中的class进行update 操作,应该怎么办?

有人说把代码里面的after改为before

改了之后,的确插入语句不会报错,但问题就变成这样了。
插入第一个学生,班级为99,并不会触发触发器修改班级为1
插入第二个学生,班级为任意,这样才能触发触发器,修改第一个学生的班级为1
这样显然没有解决问题
那么有没有办法能够在插入第一个学生,班级为99的时候,就触发触发器修改其班级为1呢?

只能求助万能牛逼的各位网友了,感激不尽。

解决ORA-04091触发器/函数不能读它,需用oracle的自治事务。
举例如下:
create or replace trigger TR_U_ID_SYNCH
before update on COMPANY referencing old as old_value
new as new_value
for each row
declare
tId company.id%type;
PRAGMA AUTONOMOUS_TRANSACTION;
begin
if :new_value.U_ID is not null and :new_value.U_ID!=ld_value.U_ID then
select t.t_id into tId from company t where t.id= :new_value.U_ID;
:new_value.P_ID :=:new_value.U_ID;
:new_value.T_ID :=tId;
end if;
COMMIT;
end TR_CO_GB_ID_SYNCH;
参考技术A create or replace trigger tri_insert
before insert on student
for each row
when (new.class=99)
begin
:new.class:=1;
end tri_insert;本回答被提问者采纳

编译触发器时出现 Oracle 错误 ORA-00922

【中文标题】编译触发器时出现 Oracle 错误 ORA-00922【英文标题】:Oracle Error ORA-00922 While Compiling Trigger 【发布时间】:2020-08-17 13:49:25 【问题描述】:

我在表中有一个 varchar2 数据类型列。用户只能在该列中插入数字,我不想更改为数字。有时在手动插入此列的数据时,用户可以在列中留出空格。我创建了一个触发器来避免它。我写的触发器如下。

CREATE OR REPLACE trigger_name
BEFORE INSERT ON table
FOR EACH ROW 
BEGIN 
  IF :new.column != TRIM(:new.column) THEN
     :new.column := TRIM(:new.column);
  ELSE
   dbms_output.put_line(:new.column || ' is suitable for jobid');
END IF;
END;

编译上述代码时出现如下错误。

“ORA-00922:缺少或无效选项”

提前致谢。

【问题讨论】:

不幸的是,它不断出错。我也删除了 8 号末尾的分号,但我无法修复它。 首先,我只删除了第 6 次,但出现错误。然后我也删除了第8个,但是我又出错了。 对不起,我看错了,在 CREATE OR REPLACE 之后缺少 TRIGGER 关键字的语法存在问题,我认为表名应该是一个代表。由于无法创建名称为 table 的表。您需要该列的浮点数,还是只需要数字(整数)? 不客气。如果您坚持不更改数据类型,我认为添加检查约束可能比使用触发器更好。您需要该列的浮点数,还是只需要数字(整数)? 您的触发器不会从输入的数据中删除所有空格;使用时,TRIM 会删除前导和尾随空格。但是,第一个数字和最后一个数字之间不会有任何空格。所以字符串'123'变成'123',字符串'12 3'没有,空格仍然存在。另外,您如何使用户无法输入其他非数字字符。如果你能做到这一点,为什么不也不允许进入空间。顺便说一句,您的触发器可以简化为单行 :new.column := trim(:new.column); 以产生完全相同的结果,除了开发之外没人会看到的消息. 【参考方案1】:

错误ORA-00922是由缺少关键字TRIGGER引起的,正如Barbaros Özhan所指出的那样。只需添加它,假设您的表名和列名正确,那么就可以了。


但进一步查询,您似乎想替换用户为该列输入的所有空格。如果是这样,这个触发器可以做到:

CREATE OR REPLACE TRIGGER trigger_name
BEFORE INSERT ON table_name
  FOR EACH ROW
BEGIN
  IF :new.column_name != REPLACE(:new.column_name,' ','') THEN
    :new.column_name := REPLACE(:new.column_name,' ','');
  ELSE
    dbms_output.put_line(:new.column_name|| ' is suitable for jobid');
  END IF;
END;

我添加了缺少的关键字trigger。 只需将 table_namecolumn_name 替换为正确的名称即可。

【讨论】:

以上是关于Oracle数据库如何解决ORA-04091触发器/函数不能读它的问题的主要内容,如果未能解决你的问题,请参考以下文章

oracle 触发器 ORA-04091

如何在Oracle触发器中使用查询语句

ora-04091 表正在变异-

仅在 old = new 上进行选择时获取变异表 (ORA-04091)

如何修复 ORA-04091:表正在变异,触发器/函数可能看不到它?

使用 JDBC、spring 框架和 oracle 时出现 ORA04091-table is mutating 错误