#oracle #plsql
#Oracle #plsql
Вопрос:
«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, я не получу сообщение, но мне нужно показать код используемого. Что я делаю не так.
Заранее благодарю.
Комментарии:
1. Используйте
:new.emp_no
. Кроме того: использованиеmax() 1
для генерации идентификатора — действительно плохая идея.2. Для предотвращения мутации в oracle вы можете использовать составной триггер, но здесь вам это не нужно. Просто удалите select в emp и используйте :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>