Как найти зависимости внешнего ключа, указывающие на одну запись в Oracle? - PullRequest
19 голосов
/ 24 марта 2010

У меня очень большая база данных Oracle с множеством таблиц и миллионами строк. Мне нужно удалить один из них, но я хочу убедиться, что удаление его не повредит любые другие зависимые строки, которые указывают на него как запись внешнего ключа. Есть ли способ получить список всех других записей или, по крайней мере, схем таблиц, которые указывают на эту строку? Я знаю, что мог бы просто попытаться удалить его сам и поймать исключение, но я не буду сам запускать сценарий, и мне нужно, чтобы он запускался чистым с первого раза.

У меня есть инструменты SQL Developer от Oracle и PL / SQL Developer от AllRoundAutomations.

Заранее спасибо!

Ответы [ 6 ]

31 голосов
/ 02 октября 2012

Вот мое решение перечислить все ссылки на таблицу:

select
  src_cc.owner as src_owner,
  src_cc.table_name as src_table,
  src_cc.column_name as src_column,
  dest_cc.owner as dest_owner,
  dest_cc.table_name as dest_table,
  dest_cc.column_name as dest_column,
  c.constraint_name
from
  all_constraints c
inner join all_cons_columns dest_cc on
  c.r_constraint_name = dest_cc.constraint_name
  and c.r_owner = dest_cc.owner
inner join all_cons_columns src_cc on
  c.constraint_name = src_cc.constraint_name
  and c.owner = src_cc.owner
where
  c.constraint_type = 'R'
  and dest_cc.owner = 'MY_TARGET_SCHEMA'
  and dest_cc.table_name = 'MY_TARGET_TABLE'
  --and dest_cc.column_name = 'MY_OPTIONNAL_TARGET_COLUMN'
;

С этим решением у вас также есть информация о том, какой столбец какой таблицы ссылается на какой столбец вашей целевой таблицы (и вы можете фильтровать по ней).

26 голосов
/ 24 марта 2010

Я всегда смотрю на внешние ключи для стартовой таблицы и возвращаюсь. Инструменты БД обычно имеют узел зависимостей или ограничений. Я знаю, что у PL / SQL Developer есть способ увидеть FK, но с тех пор, как я его использовал, прошло много времени, поэтому я не могу это объяснить ...

просто замените XXXXXXXXXXXX на имя таблицы ...

/* The following query lists all relationships */ 

select
 a.owner||'.'||a.table_name "Referenced Table"
,b.owner||'.'||b.table_name "Referenced by"
,b.constraint_name "Foreign Key"
from all_constraints a, all_constraints b 
where 
b.constraint_type = 'R'
and a.constraint_name = b.r_constraint_name 
and b.table_name='XXXXXXXXXXXX' -- Table name 
order by a.owner||'.'||a.table_name
8 голосов
/ 13 февраля 2014

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

SELECT LPAD(' ',4*(LEVEL-1)) || table1 || ' <-- ' || table2 tables, table2_fkey
FROM
  (SELECT a.table_name table1, b.table_name table2, b.constraint_name table2_fkey
  FROM user_constraints a, user_constraints b 
  WHERE a.constraint_type IN('P', 'U') 
  AND b.constraint_type = 'R' 
  AND a.constraint_name = b.r_constraint_name 
  AND a.table_name != b.table_name
  AND b.table_name <> 'MYTABLE')
CONNECT BY PRIOR  table2 = table1 AND LEVEL <= 5
START WITH table1 = 'MYTABLE';

Это дает такой результат при использовании SHIPMENT как MYTABLE в моей базе данных:

SHIPMENT <-- ADDRESS
SHIPMENT <-- PACKING_LIST
    PACKING_LIST <-- PACKING_LIST_DETAILS
    PACKING_LIST <-- PACKING_UNIT
        PACKING_UNIT <-- PACKING_LIST_ITEM
    PACKING_LIST <-- PO_PACKING_LIST
...
3 голосов
/ 24 марта 2010

Мы можем использовать словарь данных для идентификации таблиц, которые ссылаются на первичный ключ рассматриваемой таблицы. Исходя из этого, мы можем сгенерировать некоторый динамический SQL, чтобы запросить в этих таблицах значение, которое мы хотим zap:

SQL> declare
  2      n pls_integer;
  3      tot pls_integer := 0;
  4  begin
  5      for lrec in ( select table_name from user_constraints
  6                    where r_constraint_name = 'T23_PK' )
  7      loop
  8          execute immediate 'select count(*) from '||lrec.table_name
  9                              ||' where col2 = :1' into n using &&target_val;
 10          if n = 0 then
 11              dbms_output.put_line('No impact on '||lrec.table_name);
 12          else
 13              dbms_output.put_line('Uh oh! '||lrec.table_name||' has '||n||' hits!');
 14          end if;
 15          tot := tot + n;
 16      end loop;
 17      if tot = 0
 18      then
 19          delete from t23 where col2 = &&target_val;
 20          dbms_output.put_line('row deleted!');
 21      else
 22          dbms_output.put_line('delete aborted!');
 23      end if;
 24  end;
 25  /
Enter value for target_val: 6
No impact on T34
Uh oh! T42 has 2 hits!
No impact on T69
delete aborted!

PL/SQL procedure successfully completed.

SQL>

Этот пример немного обманывает. Имя целевого первичного ключа жестко закодировано, и столбец ссылок имеет одинаковое имя во всех зависимых таблицах. Решение этих проблем оставлено читателю в качестве упражнения;)

0 голосов
/ 28 августа 2015

Ограничения Oracle используют индексы таблиц для ссылки на данные.Чтобы выяснить, какие таблицы ссылаются на одну таблицу, просто ищите индекс в обратном порядке.

/* Toggle ENABLED and DISABLE status for any referencing constraint: */ 

select 'ALTER TABLE '||b.owner||'.'||b.table_name||' '||
        decode(b.status, 'ENABLED', 'DISABLE ', 'ENABLE ')||
       'CONSTRAINT '||b.constraint_name||';' 
  from all_indexes a,
       all_constraints b
 where a.table_name='XXXXXXXXXXXX' -- Table name 
   and a.index_name = b.r_constraint_name;

Obs .: Отключение ссылок значительно сокращает время выполнения команд DML (обновление, удаление ивставить).

Это может очень помочь в массовых операциях, когда вы знаете, что все данные согласованы.

/* List which columns are referenced in each constraint */

select ' TABLE "'||b.owner||'.'||b.table_name||'"'||
        '('||listagg (c.column_name, ',') within group (order by c.column_name)||')'|| 
        ' FK "'||b.constraint_name||'" -> '||a.table_name||
        ' INDEX "'||a.index_name||'"'
        "REFERENCES"
  from all_indexes a,
       all_constraints b,
       all_cons_columns c
 where rtrim(a.table_name) like 'XXXXXXXXXXXX' -- Table name 
   and a.index_name = b.r_constraint_name
   and c.constraint_name = b.constraint_name
 group by b.owner, b.table_name, b.constraint_name, a.table_name, a.index_name
 order by 1;
0 голосов
/ 18 июня 2015

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

   SELECT referenced_table
         ,MAX(lvl) for_deleting
         ,MIN(lvl) for_inserting
   FROM
         ( -- Hierarchy of dependencies
         SELECT LEVEL lvl
               ,t.table_name referenced_table
               ,b.table_name referenced_by
         FROM user_constraints A
         JOIN user_constraints b 
               ON  A.constraint_name = b.r_constraint_name
               and b.constraint_type = 'R'
         RIGHT JOIN user_tables t
               ON  t.table_name = A.table_name
         START WITH b.table_name IS NULL
         CONNECT BY b.table_name = PRIOR t.table_name
         )
   GROUP BY referenced_table
   ORDER BY for_deleting, for_inserting;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...