Добро пожаловать, Гость
Логин: Пароль: Запомнить меня
Администрирование Oracle Database:
- Установка и настройка базы данных
- Обновление, применение патчей
- Оптимизация, настройка производительности
- Обучение, подготовка персонала, оптимизация
  • Страница:
  • 1
  • 2
  • 3

ТЕМА:

oracle cascade delete 12 года 1 мес. назад #4336

  •  аватар Автор темы
  • Посетитель
  • Посетитель
Всем привет.
Такой вот вопрос: что-то не могу в документации найти ответа.

Есть родительская и дочерняя таблички. В дочерней - внешний ключ к родительской с кляузой ON DELETE CASCADE.
Для обеих таблиц создан statement-level триггер BEFORE DELETE.

Каков будет порядок вызова этих триггеров в случае, когда мы выполняем удаление данных из родительской таблицы???

Опытным путем я обнаружил, что первым в этом случае срабатывает триггер BEFORE DELETE для дочерней таблицы. Проверял в 9-ке и в 10-ке. Однако в документации, повторяюсь, на эту тему ничего не нашел.

Что скажете?
Спасибо.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Re: oracle cascade delete 12 года 1 мес. назад #4337

  •  аватар
  • Посетитель
  • Посетитель

Опытным путем я обнаружил, что первым в этом случае срабатывает триггер BEFORE DELETE для дочерней таблицы. Проверял в 9-ке и в 10-ке. Однако в документации, повторяюсь, на эту тему ничего не нашел.


The Execution Model for Triggers and Integrity Constraint Checking:

Statement triggers fired due to DELETE CASCADE and DELETE SET NULL are fired before and after the user DELETE statement, not before and after the individual enforcement statements. This prevents those statement triggers from encountering mutating errors.



Another words, it does not matter how many child table rows are deleted due to CASCADE DELETE, child table BEFORE DELETE trigger is executed only once - before DELETE statement on a parent table (user DELETE statement).

SY.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Re: oracle cascade delete 12 года 1 мес. назад #4338

  •  аватар Автор темы
  • Посетитель
  • Посетитель

..are fired before and after the user DELETE statement




Yeah, I saw this in documentation. But does it mean I am right? And BEFORE DELETE for child table is always called first???

Please, look at this Tom Kyte answer for very similar question. Kyte claims that there's no specific firing order in this case. I suppose he means that,
Oracle 9iR2 Database concepts
Note: Although triggers of different types are fired in a specific order, triggers of the same type for the same statement are not guaranteed to fire in any specific order. For example, all BEFORE row triggers for a single UPDATE statement may not always fire in the same order. Design your applications so they do not rely on the firing order of multiple triggers of the same type.


As for me, I suppose this is true only if these "same-type" triggers are defined on the same table. Then I clearly understand that firing order is unpredictable. But I have two tables, as you can see...

So, what do you think?

Regards.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Re: oracle cascade delete 12 года 1 мес. назад #4339

  •  аватар
  • Посетитель
  • Посетитель

Yeah, I saw this in documentation. But does it mean I am right? And BEFORE DELETE for child table is always called first???



Yes, in CASCADE DELETE/SET NULL context (otherwise BEFORE DELETE for child table trigger does not fire at all ). And documentation clearly states it - see section in red in my reply. Again, when delting from a parent table Oracle will check if any child tables have on DELETE CASCADE. For ones that do, Oracle will check for statement level BEFORE DELETE triggers. If there are any, Oracle will execute each of them not once for each delete statement (keep in mind, there will be as many child table delete statements as there are parent records to delete) but once, before deleting that child records (keep in mind, row level trigger behavior does not change - they will fire once for each deleted child record). After deleting all child records, Oracle will execute parent table BEFORE DELETE trigger. And only then, which is important, Oracle will execute any AFTER DELETE triggers on DELETE CASCADE child tables. Next step is AFTER DELETE trigger on parent table:

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Re: oracle cascade delete 12 года 1 мес. назад #4340

  •  аватар
  • Посетитель
  • Посетитель
Видать сильно от версии зависит,
или я гдето-то ошибся
Сначала результат ниже тестOracle8i Enterprise Edition Release 8.1.6.0.0 - Production

With the Partitioning option
JServer Release 8.1.6.0.0 - Production

SQL> delete parent;
Child_child before DELETE.
Child_child before DELETE.
Child_child before DELETE.
Child_child before DELETE.
Child_child after DELETE.
Child_child after DELETE.
Child_child after DELETE.
Child_child after DELETE.


Тест


Тест добавил табличку parent-child1-child3SQL> drop table child3;

Table dropped.

SQL> drop table child2;

Table dropped.

SQL> drop table child1;

Table dropped.

SQL> drop table parent;

Table dropped.

SQL> create table parent(id int primary key);

Table created.

SQL> CREATE TRIGGER PARENT_BD_TRG
2 BEFORE DELETE ON PARENT
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE('Parent before DELETE.');
5 END;
6 /

Trigger created.

SQL> CREATE or replace TRIGGER PARENT_AD_TRG
2 AFTER DELETE ON PARENT
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE('Parent after DELETE.');
5 END;
6 /

Trigger created.

SQL> create table child1(id int primary key,id_ref,
2 constraints f1 foreign key (id_ref) REFERENCES PARENT on delete cascade)
3 /

Table created.

SQL> create table child2(id_ref,
2 constraints f2 foreign key (id_ref) REFERENCES PARENT on delete cascade)
3 /

Table created.

SQL> create table child3(id_ref,
2 constraints f3 foreign key (id_ref) REFERENCES child1 on delete cascade)
3 /

Table created.

SQL> CREATE or replace TRIGGER CHILD1_BD_TRG
2 BEFORE DELETE ON child1
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE('Child1 before DELETE.');
5 END;
6 /

Trigger created.

SQL> CREATE or replace TRIGGER CHILD2_BD_TRG
2 BEFORE DELETE ON child2
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE('Child2 before DELETE.');
5 END;
6 /

Trigger created.

SQL> CREATE or replace TRIGGER CHILD3_BD_TRG
2 BEFORE DELETE ON child3
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE('Child_child before DELETE.');
5 END;
6 /

Trigger created.

SQL> CREATE or replace TRIGGER CHILD1_AD_TRG
2 AFTER DELETE ON CHILD1
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE('Child1 after DELETE.');
5 END;
6 /

Trigger created.

SQL> CREATE or replace TRIGGER CHILD2_AD_TRG
2 AFTER DELETE ON CHILD2
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE('Child2 after DELETE.');
5 END;
6 /

Trigger created.

SQL> CREATE or replace TRIGGER CHILD3_AD_TRG
2 AFTER DELETE ON CHILD3
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE('Child_child after DELETE.');
5 END;
6 /

Trigger created.

SQL> select TRIGGER_NAME,TRIGGER_TYPE,TABLE_NAME from user_triggers
2 where table_name in ('PARENT','CHILD1','CHLID2','CHILD3');

TRIGGER_NAME TRIGGER_TYPE TABLE_NAME




CHILD1_AD_TRG AFTER STATEMENT CHILD1
CHILD1_BD_TRG BEFORE STATEMENT CHILD1
CHILD3_AD_TRG AFTER STATEMENT CHILD3
CHILD3_BD_TRG BEFORE STATEMENT CHILD3
PARENT_AD_TRG AFTER STATEMENT PARENT
PARENT_BD_TRG BEFORE STATEMENT PARENT

6 rows selected.

SQL> insert into parent values(1);

1 row created.


SQL> insert into child1 values(1,1);

1 row created.

SQL> insert into child2 values(1);

1 row created.


SQL> insert into child3 values(1);

1 row created.

SQL> commit;

Commit complete.

SQL> delete parent;
Child_child before DELETE.
Child_child before DELETE.
Child_child before DELETE.
Child_child before DELETE.
Child_child after DELETE.
Child_child after DELETE.
Child_child after DELETE.
Child_child after DELETE.

1 row deleted.

SQL> rollback;

Rollback complete.

SQL> insert into parent values(2);

1 row created.

SQL> insert into child1 values(2,2);

1 row created.

SQL> insert into child2 values(2);

1 row created.

SQL> insert into child3 values(2);

1 row created.

SQL> commit;

Commit complete.

SQL> delete parent;
Child_child before DELETE.
Child_child before DELETE.
Child_child before DELETE.
Child_child before DELETE.
Child_child after DELETE.
Child_child after DELETE.
Child_child after DELETE.
Child_child after DELETE.

2 rows deleted.

SQL> rollback;

Rollback complete.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Re: oracle cascade delete 12 года 1 мес. назад #4341

  •  аватар Автор темы
  • Посетитель
  • Посетитель
Я что-то не пойму: у Вас что, родительский BEFORE-триггер совсем не вызывается?...


Вообще говоря, я склонен доверять SY. И мой исходный вопрос, в общем-то, важен для той задачи, которую я сейчас решаю. Одна из подзадач - ведение "лога" удаленных записей: т.е. записи, удаляемые как из родительской, так и из дочерней таблицы, вставляются в другую табличку в триггерах FOR EACH ROW. Однако загвоздка в том, что если записи дочерней таблицы удаляются не напрямую, а вследствие каскадного удаления, то помещать их в лог не нужно. Надеюсь, я ясно выражаюсь.

Так вот, у меня сейчас есть два варианта решения этой проблемы: простой и более громоздкий. Простой предполагает использование переменной пакета и двух дополнительных before delete триггеров соответственно для родительской и дочерних таблиц. Однако, если порядок вызова последних триггеров при удалении из родительской таблицы все же непредсказуем, то страшновато такое использовать

Насчет Вашего случая, могу сказать, что по поводу восьмерки на Металинке были похожие обсуждения.

Интересно было бы услышать еще мнения.
Спасибо.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

  • Страница:
  • 1
  • 2
  • 3
Время создания страницы: 0.224 секунд