“ 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,则不会收到消息,但需要显示受雇人员的代码。我做错了什么。
谢谢。
答案 0 :(得分: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>