Построение табличного графа зависимостей с помощью рекурсивного запроса

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

START WITH Table_Name=:tablename

Он не возвращает все дерево.

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
5
0
11 052
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Самый простой способ сделать это - скопировать всю информацию FK в простую таблицу с двумя столбцами (родительская, дочерняя), а затем использовать следующий алгоритм:

while (rows left in that table)
  list = rows where table name exists in child but not in parent
  print list
  remove list from rows

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

P.S. Убедитесь, что вы не вставляете саморегулирующиеся таблицы в исходный список (дочерний = родительский).

Ответ принят как подходящий

    select parent, child, level from (
select parent_table.table_name parent, child_table.table_name child
 from user_tables      parent_table,
      user_constraints parent_constraint,
      user_constraints child_constraint,
      user_tables      child_table
where parent_table.table_name = parent_constraint.table_name
  and parent_constraint.constraint_type IN( 'P', 'U' )
  and child_constraint.r_constraint_name = parent_constraint.constraint_name
  and child_constraint.constraint_type   = 'R'
  and child_table.table_name = child_constraint.table_name
  and child_table.table_name != parent_table.table_name
)
start with parent = 'DEPT'
connect by prior child = parent

должен работать (конечно, заменить имя таблицы), предполагая, что все находится в одной схеме. Используйте версии DBA_ таблиц словаря данных и условия для столбцов OWNER и R_OWNER, если вам нужно обрабатывать зависимости между схемами. При дальнейшем размышлении, это также не учитывает самореферентные ограничения (т.е. ограничение таблицы EMP, которое столбец MGR ссылается на столбец EMPNO), поэтому вам придется изменить код для обработки этого случая, если вам нужно иметь дело с самореференциальными ограничениями.

В целях тестирования я добавил несколько новых таблиц в схему SCOTT, которые также ссылаются на таблицу DEPT (включая зависимость внуков)

SQL> create table dept_child2 (
  2  deptno number references dept( deptno )
  3  );

Table created.

SQL> create table dept_child3 (
  2    dept_child3_no number primary key,
  3    deptno number references dept( deptno )
  4  );

Table created.

SQL> create table dept_grandchild (
  2    dept_child3_no number references dept_child3( dept_child3_no )
  3  );

Table created.

и проверил, что запрос вернул ожидаемый результат

SQL> ed
Wrote file afiedt.buf

  1  select parent, child, level from (
  2  select parent_table.table_name parent, child_table.table_name child
  3   from user_tables      parent_table,
  4        user_constraints parent_constraint,
  5        user_constraints child_constraint,
  6        user_tables      child_table
  7  where parent_table.table_name = parent_constraint.table_name
  8    and parent_constraint.constraint_type IN( 'P', 'U' )
  9    and child_constraint.r_constraint_name = parent_constraint.constraint_name
 10    and child_constraint.constraint_type   = 'R'
 11    and child_table.table_name = child_constraint.table_name
 12    and child_table.table_name != parent_table.table_name
 13  )
 14  start with parent = 'DEPT'
 15* connect by prior child = parent
SQL> /

PARENT                         CHILD                               LEVEL
------------------------------ ------------------------------ ----------
DEPT                           DEPT_CHILD3                             1
DEPT_CHILD3                    DEPT_GRANDCHILD                         2
DEPT                           DEPT_CHILD2                             1
DEPT                           EMP                                     1

Когда я запускаю этот запрос, я получаю ORA-01437: cannot have join with CONNECT BY

Tulains Córdova 20.06.2013 22:57

@ user1598390 - Вы хотите сказать, что когда вы запускаете точный тестовый пример, который я опубликовал, вы получаете сообщение об ошибке? Или вы делаете что-то (даже немного) другое? Без вашего кода маловероятно, что мы сможем чем-то вам помочь. Вероятно, вам понадобится создать новый вопрос, в котором вы можете опубликовать точный запрос, который вы используете, и, в идеале, показать, что он не работает, с некоторыми образцами таблиц, которые вы публикуете.

Justin Cave 20.06.2013 23:01

Я копирую ваш SQL, вставляю его в клиент Oracle (PL / SQL Developer), затем нажимаю F8, чтобы запустить его, и получаю сообщение об ошибке.

Tulains Córdova 20.06.2013 23:03

@ user1598390 - Хорошо, значит, вы используете схему SCOTT по умолчанию, вы создали таблицы, которые я создал здесь, и выполнили точно такой же оператор SQL, который я опубликовал, чтобы получить зависимости таблицы DEPT? Как видите, у меня это сработало. Какую версию Oracle вы используете?

Justin Cave 20.06.2013 23:06

Нет, я использую настоящую производственную схему с множеством таблиц и зависимостей. Версия Oracle - 8.1.7.

Tulains Córdova 20.06.2013 23:10

@ user1598390 - Вам подходит простой пример, который я опубликовал? 8.1.7 была дериминирована в течение какого, десятилетия? У меня уже много лет не было доступа к базе данных 8.1.7. Так что я не был бы шокирован, если бы древняя версия Oracle имела более ограниченную поддержку пункта connect by.

Justin Cave 20.06.2013 23:15

Другие вопросы по теме