ORA-04091: 表 JOSEP.EMP 正在变异,触发器/函数可能看不到它

Posted

技术标签:

【中文标题】ORA-04091: 表 JOSEP.EMP 正在变异,触发器/函数可能看不到它【英文标题】:ORA-04091: table JOSEP.EMP is mutating, trigger/function may not see it 【发布时间】:2019-04-11 19:17:59 【问题描述】:

“ORA-04091:表 JOSEP.EMP 正在变异,触发器/函数可能看不到它”

我必须显示一条消息,其中包含旧工资和新工资,以及其中的受雇人代码(emp_no),但我无法做到。

create or replace trigger emp_AU 
after update of salario 
on emp for each row
    declare
    v_emp_no emp.emp_no%type;  
    begin
    select emp_no into v_emp_no FROM emp;
    insert into auditaemple VALUES ((select count(*) from auditaemple)+1, 'El salario del empleado '||v_emp_no||'antes era de '||:old.salario||' y ahora será '||:new.salario, sysdate);
    end emp_AU;

这样做会产生“ORA-04091:”错误。如果我消除 v_emp_no,我将不会收到消息,但我需要显示雇用的代码。我做错了什么。

提前致谢。

【问题讨论】:

使用:new.emp_no。此外:使用max()+1 生成ID 真的是个坏主意。 为了避免oracle上的突变,您可以使用复合触发器,但在这里您不需要这样做。只需删除 emp 上的 select 并使用 :new 就像之前的评论一样。对于主键递增列,请使用序列。 【参考方案1】:

导致变异表错误的原因是在从表中选择数据时 在事务的中间 - 您正在更新它,并且 - 同时 - 从中​​选择.由于您不能这样做(嗯,您可以,有一些变通方法,但您不应该这样做),Oracle 不会让您这样做。

无需选择emp_no;您已经拥有它 - 使用 :new 伪记录引用它。此外,按照您的说法,您会收到 TOO-MANY-ROWS 错误,因为没有 WHERE 子句将结果集限制为单行。

不要使用count + 1(也不要使用max + 1 或类似的“技术”),尤其是当您要填充一个应该是唯一的列时。只要它可以在单用户环境中工作,它就会(迟早)在多用户环境中失败。使用序列(或者,如果您的数据库支持,则使用标识列)。

这是一个工作示例,说明您可能如何做到这一点。

首先,测试用例:

SQL> create table temp as select empno emp_no, sal salario
  2                       from emp where deptno = 10;

Table created.

SQL> create table auditaemple (id number, text varchar2(100), datum date);

Table created.

SQL> create sequence seqa;

Sequence created.

触发器:

SQL> create or replace trigger trg_bu_emp
  2    before update of salario on temp
  3    for each row
  4  begin
  5    insert into auditaemple (id, text, datum)
  6      values (seqa.nextval,
  7              'El salario del empleado '||:new.emp_no||' antes era de '||
  8               :old.salario||' y ahora será '||:new.salario, sysdate);
  9  end;
 10  /

Trigger created.

测试:

SQL> select * from temp;

    EMP_NO    SALARIO
---------- ----------
      7782       2450
      7839       5000
      7934       1300

SQL> update temp set salario = 9000 where emp_no = 7839;

1 row updated.

SQL> select * From auditaemple;

        ID TEXT                                     DATUM
---------- ---------------------------------------- ----------------
         1 El salario del empleado 7839 antes era d 11.04.2019 21:47
           e 5000 y ahora será 9000


SQL>

【讨论】:

以上是关于ORA-04091: 表 JOSEP.EMP 正在变异,触发器/函数可能看不到它的主要内容,如果未能解决你的问题,请参考以下文章

ORA-04091: 表名正在变异

ORA-04091: 表 [blah] 正在变异,触发器/函数可能看不到它

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

ORA-04091:表正在变异,触发器/函数可能看不到它,ORA-06512:,ORA-06512:在“SYS.DBMS_SQL”,第 1721 行

ORA-04091 表 ODB.EMPLOYEE 正在变异,触发器/函数可能看不到它。我的触发器有问题吗?

oracle 触发器 ORA-04091