среда, 20 апреля 2016 г.

Удаление записи и всех связанных данных из других таблиц

Иногда бывает нужно удалить запись, но срабатывает констрейнт о том что есть подчиненные записи. И эта иерархия может быть очень длинная. Конечно, при использовании форенкеев с каскадным удалением, такой проблемы не возникает, но что если используются обычные форенкеи. Для решения данной проблемы, можно использовать следующий скрипт:

create table list_of_constraints as
select ddl_constraint
     , substr(replace(ddl_constraint, ' ADD ', ' DROP '), 1, instr(ddl_constraint, ' FOREIGN KEY ')) as drop_constraint
     , replace(ddl_constraint, ' ENABLE', ' ON DELETE CASCADE ENABLE') as cascade_constraint
from (select lpad(' ', 2*(level-1)) || table_name as table_name
             , id
             , parent_id
             , constraint_name
             , delete_rule
             , r_constraint_name
             , decode(constraint_type, 'R', dbms_metadata.get_ddl('REF_CONSTRAINT', constraint_name)) ddl_constraint
          from (select case
                         when constraint_type = 'R' then (select constraint_name
                                                            from user_constraints urco
                                                           where urco.table_name = urcs.table_name
                                                             and urco.constraint_type = 'P')
                         else urcs.constraint_name
                       end as id
                     , urcs.r_constraint_name as parent_id
                     , urcs.table_name
                     , urcs.constraint_type
                     , urcs.constraint_name
                     , urcs.r_constraint_name
                     , urcs.delete_rule
                  from user_constraints urcs
                 where constraint_type in ('P', 'U', 'R')) obtr
        connect by nocycle prior obtr.id = obtr.parent_id
          start with obtr.table_name = 'AAAA'
                 and obtr.constraint_type in ('P'))
where ddl_constraint is not null
  and delete_rule = 'NO ACTION'
/
---
begin
  for r in (select drop_constraint, cascade_constraint from list_of_constraints)
  loop
    execute immediate r.drop_constraint;
    execute immediate r.cascade_constraint;
  end loop;
end;
/
--- DELETE ---------------------------------------------------------------------
delete from AAAA where name = 'bbbb'
/
--------------------------------------------------------------------------------
---
begin
  for r in (select drop_constraint, ddl_constraint from list_of_constraints)
  loop
    execute immediate r.drop_constraint;
    execute immediate r.ddl_constraint;
  end loop;
end;
/
drop table list_of_constraints

/
В этом скрипте, мы вычисляем все подчиненные таблицы для таблице АААА. При этом во временную таблицу list_of_constraints  мы записываем скрипты для пересоздания уже существующих форенкеев на форенкеи с каскадным удалением.
После пересоздания форенкеев, мы удаляем запись из таблицы АААА и потом восстанавливаем первоначальное состояние форенкеев.

Комментариев нет:

Отправить комментарий