Чому я не отримую мутуючу помилку таблиці в тригері?


11

Відомо (або, принаймні, було) відомо, що ви не можете використовувати оператори DML у мутаційній таблиці всередині тригера. Витяг з документації Oracle :

Таблиця, що мутує, - це таблиця, яка модифікується оператором UPDATE, DELETE або INSERT, або таблиця, яка може бути оновлена ​​ефектами обмеження DELETE CASCADE.

Сеанс, який видав оператор запуску, не може запитувати або змінювати мутуючу таблицю. Це обмеження не дозволяє тригеру бачити непослідовний набір даних.

Однак я не можу зрозуміти, чому цей демо-тригер не виходить із помилкою "мутаційна таблиця", коли я виконую за insert into empдопомогою SQL Developer або SQL * Plus:

CREATE OR REPLACE TRIGGER emp_bri   
  BEFORE INSERT ON emp 
    FOR EACH ROW
BEGIN

  SELECT max(id) + 1 INTO :NEW.id FROM emp;
  UPDATE emp SET salary = 5000;

END emp_bri;

Вставка успішно завершується наступним idзначенням та оновлює всі empзаписи. Я використовую Oracle Database 11g Enterprise Edition випуску 11.2.0.1.0. Я читав про складні тригери, але зразок не використовує їх.


1
Не пов'язане з вашим запитанням, але: НЕ використовуйте select max(id)для призначення унікальних номерів. Просто ні. Це просто неправильно, і він також не буде масштабуватися.
a_horse_with_no_name

Так, я це знаю :) Приклад, мабуть, не дуже хороший в цьому випадку ... Значення для автоматичного підвищення обов'язково повинні бути реалізовані, використовуючи послідовності та тригери.
Центурион

Це впевнено дивно. Btw: ось приклад SQLFiddle sqlfiddle.com/#!4/9e59f/2
a_horse_with_no_name

Дякуємо за обмін інформацією, класне посилання. Не знав, що існує такий веб-сайт для тестування Oracle SQL :)
Centurion

a_horse_with_no_name: Ще один приклад: Fiddle-test-2 (SET зарплата = зарплата + 10)
ypercubeᵀᴹ

Відповіді:


12

Є виняток. Коли ви визначаєте before insertтригер рівня рядків на таблиці та видаєте одне INSERTтвердження про рядки , table is mutatingпомилка не буде підвищена. Але якщо визначити один і той же тип тригера і видати багаторядковий INSERTоператор, помилка буде підвищена. Ось приклад:

SQL> create table TB_TR_TEST(
  2    col1 number,
  3    col2 number
  4  )
  5  ;

Table created

SQL> create or replace trigger TR_TB_TR_TEST
  2  before insert on TB_TR_TEST
  3  for each row
  4  begin
  5    SELECT max(col1) + 1 INTO :NEW.col1
  6      FROM TB_TR_TEST;
  7    UPDATE TB_TR_TEST SET col2 = 5000;
  8  end;
  9  /

Trigger created

Ось однорядковий insertвислів, який не призведе до виникнення мутуючої помилки таблиці:

SQL> insert into TB_TR_TEST(col1, col2) values(1,2);

1 row inserted

SQL> insert into TB_TR_TEST(col1, col2) values(3,5);

1 row inserted

SQL> commit;

Commit complete

Ось оператор вставлення з декількома рядками, який призведе до помилки мутації таблиці:

SQL> insert into TB_TR_TEST(col1, col2)
  2    select 1, 2
  3      from dual;

insert into TB_TR_TEST(col1, col2)
  select 1, 2
    from dual

ORA-04091: table HR.TB_TR_TEST is mutating, trigger/function may not see it
ORA-06512: at "HR.TR_TB_TR_TEST", line 2
ORA-04088: error during execution of trigger 'HR.TR_TB_TR_TEST'

Це, здається, є винуватцем. Чи є у вас посібник у посібнику щодо такої поведінки?
a_horse_with_no_name

@a_horse_with_no_name, якщо у вас є доступ до support.oracle.com, знайдіть ID 132569.1( ORA-4091 on BEFORE ROW TRIGGER with INSERT .. into SELECT statement).
Микола Краснов

2
Спасибі. Досить цікавим цей виняток здається лише задокументованим у посібниках 8i (!): Docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/… (розділ " " Мутація та обмеження таблиць ") Я можу" не знайдіть цю заяву в поточних посібниках
a_horse_with_no_name
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.