2016-05-12 5 views
0

Мне сложно найти простой способ удалить все дочерние записи родительского идентификатора. В дочерних таблицах также могут быть собственные дочерние таблицы, поэтому нам нужно удалить все записи в иерархии. Какой метод проще всего? Я мог бы вручную перейти к каждой дочерней таблице и найти ее дочерние таблицы, а затем создать скрипт, но есть слишком много таблиц и вы хотите знать более простой подход. Любая помощь ценится!Oracle - удалить все дочерние записи для родителя

ответ

2

Это в значительной степени основные ключи и внешние ключи и предложения, такие как ON DELETE CASCADE. Если еще не поздно, вы можете попробовать добавить ограничения PK и FK, прежде чем делать какие-либо удаления; то все будет легко.

ADDED: На основании дальнейшего обсуждения. Нижеприведенный запрос может быть использован для поиска всех таблиц-потомков родительской таблицы. Вероятно, запрос может быть улучшен по-разному, но это может быть начальная точка OK.

with f as (
     select constraint_name, table_name, r_constraint_name 
     from user_constraints 
     where constraint_type = 'R' 
    ), 
    p as (
     select constraint_name, table_name 
     from user_constraints 
     where constraint_type = 'P' 
    ), 
    j (child_table, f_key, parent_table, p_key) as (
     select f.table_name, f.constraint_name, p.table_name, f.r_constraint_name 
     from p join f on p.constraint_name = f.r_constraint_name 
     union all 
     select 'EMPLOYEES', (select constraint_name from p 
           where table_name = 'EMPLOYEES'), null, null from dual 
    ) 
select level as lvl, j.* 
from j 
start with parent_table is null 
connect by nocycle parent_table = prior child_table 
order by lvl, parent_table, child_table; 

«родительским» таблица в данном случае СОТРУДНИКИ и имя появляется дважды на одной и той же линии. Это может быть сделано в переменной привязки, если это необходимо. Я использовал СОТРУДНИКИ (примечание: оно должно быть во всех шапках, потому что это то, как строковые значения хранятся в системных таблицах), потому что я использовал это в стандартной схеме HR; выход:

LVL CHILD_TABLE  F_KEY    PARENT_TABLE  P_KEY 
----- ----------------- -------------------- ----------------- ----------------- 
    1 EMPLOYEES   EMP_EMP_ID_PK 
    2 DEPARTMENTS  DEPT_MGR_FK   EMPLOYEES   EMP_EMP_ID_PK 
    2 JOB_HISTORY  JHIST_EMP_FK   EMPLOYEES   EMP_EMP_ID_PK 
    3 JOB_HISTORY  JHIST_DEPT_FK  DEPARTMENTS  DEPT_ID_PK 
+0

Да, у нас уже есть внешние ключи. Мне просто нужно знать имена таблиц в иерархии и имена столбцов. Затем я могу написать скрипт, чтобы сначала удалить нижние большинство дочерних таблиц, а затем остальные соответственно. – user3224907

+1

Просто используйте каскадное удаление, как указано в названии @mathguy. Не нужно писать снизу вверх удалений – OldProgrammer

+0

Я думаю, что я понимаю, что такое OP после ... что, если FK не установлены с каскадным удалением? Ему/ей нужен способ перечислить всех потомков, чтобы убедиться, что FK настроены с помощью ON CASCADE DELETE. Для моего собственного изучения я изучаю, как это можно сделать - либо с помощью инструментов (я уверен, что они должны быть), либо с иерархическим запросом для ALL_CONSTRAINTS и ALL_CONS_COLUMNS. – mathguy

2

Рассмотрим практический пример. Скажем, у вас есть таблица с именем PARENT_TABLE:

CREATE TABLE PARENT_TABLE 
    (ID_PARENT_TABLE NUMBER 
    CONSTRAINT PK_PARENT_TABLE 
     PRIMARY KEY 
     USING INDEX, 
    PARENT_ATTR_1 NUMBER, 
    PARENT_ATTR_2 VARCHAR2(100), 
    BLAH_BLAH_BLAH VARCHAR2(50)); 

Теперь давайте говорить, что есть ребенок таблица с именем, довольно unoriginally, CHILD_TABLE:

CREATE TABLE CHILD_TABLE 
    (ID_CHILD_TABLE  NUMBER 
    CONSTRAINT PK_CHILD_TABLE 
     PRIMARY KEY 
     USING INDEX, 
    ID_PARENT_TABLE NUMBER 
    CONSTRAINT CHILD_TABLE_FK1 
     REFERENCES PARENT_TABLE(ID_PARENT_TABLE) 
     ON DELETE CASCADE, 
    CHILD_ATTR_1  NUMBER, 
    WHATEVER   VARCHAR2(100)); 

Это ограничение внешнего ключа CHILD_TABLE_FK1, который действительно делает работу здесь. Когда вы удаляете из PARENT_TABLE, база данных замечает, что CHILD_TABLE_FK1 ссылается на PARENT_TABLE (ID_PARENT_TABLE), поэтому в базе данных говорится: «Хмммм ... Я удаляю строку в PARENT_TABLE, которая имеет значение ID_PARENT_TABLE (допустим) 10 - мне интересно, это любые строки в таблице, названной этим ограничением CHILD_TABLE_FK1, которое также имеет значение ID_PARENT_TABLE 10. Ну, по Юпитеру, есть Wow - что мне делать с этим? Ну, ограничение говорит: «ON DELETE CASCADE» - ah-ha! Поэтому я просто удалю эти строки из CHILD_TABLE, у которых есть значения ID_PARENT_TABLE, которые соответствуют тому, который я удаляю, и все будет правильно с миром, реляционно говорящим ». Теперь, если каскад внешнего ключа указал ON DELETE SET NULL, тогда значения ID_PARENT_KEY в CHILD_TABLE, которые совпадали с удаляемым, были бы установлены в NULL. Кроме того, если вы не указали параметр ANY ON DELETE, база данных не знала, что делать - вы не сказали ему, чтобы УДАЛИТЬ соответствующие ссылки, и вы не сказали ему установить соответствующие ссылки на NULL, поэтому он будет бросать руки (образно) и бросать исключение (буквально), потому что у вас не может быть дочернего ключа, чей родитель больше не существует.

Обратите внимание, что вы можете продолжить это, насколько это необходимо. Скажем, у вас есть еще одна таблица GRAND_CHILD_TABLE который ссылается CHILD_TABLE:

CREATE TABLE GRAND_CHILD_TABLE 
    (ID_GRAND_CHILD_TABLE NUMBER 
    CONSTRAINT PK_GRAND_CHILD_TABLE 
     PRIMARY KEY 
     USING INDEX, 
    ID_CHILD_TABLE  NUMBER 
    CONSTRAINT GRAND_CHILD_TABLE_FK1 
     REFERENCES CHILD_TABLE(ID_CHILD_TABLE) 
     ON DELETE CASCADE, 
    what_EVER    VARCHAR2(25)); 

Теперь, когда вы удалите из PARENT_TABLE CHILD_TABLE_FK1 ограничение будет вызывать совпадающие строки в CHILD_TABLE будут удалены, а GRAND_CHILD_TABLE_FK1 ограничение будет удалять любые строки в GRAND_CHILD_TABLE которого ID_CHILD_TABLE значения соответствуют удаляемым из CHILD_TABLE.

Удачи.

Смежные вопросы