Question

J'essaie de créer un graphique de dépendance constitué de tables basées sur les clés étrangères entre elles. Ce graphique doit commencer par un nom de table arbitraire en tant que racine. Je pourrais, étant donné le nom d’une table, consulter les tables qui y font référence à l’aide de la vue all_constraints, puis rechercher les tables qui les référencent, etc., mais ce serait horriblement inefficace. J'ai écrit une requête récursive qui le fait pour toutes les tables, mais quand j'ajoute:

START WITH Table_Name=:tablename

Il ne renvoie pas l'arbre entier.

Était-ce utile?

La solution

    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

devrait fonctionner (remplacer le nom de la table, bien sûr) en supposant que tout se trouve dans le même schéma. Utilisez les versions DBA_ des tables et conditions du dictionnaire de données pour les colonnes OWNER et R_OWNER si vous devez gérer des dépendances entre schémas. Après réflexion, cela ne tient pas compte non plus des contraintes auto-référentielles (c.-à-d. Une contrainte sur la table EMP pour laquelle la colonne MGR fait référence à la colonne EMPNO). Vous devrez donc modifier le code pour gérer ce cas si vous devez gérer avec des contraintes auto-référentielles.

À des fins de test, j'ai ajouté quelques nouvelles tables au schéma SCOTT qui font également référence à la table DEPT (y compris une dépendance de petit-enfant)

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.

et a vérifié que la requête avait renvoyé le résultat attendu

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

Autres conseils

Pour ce faire, le moyen le plus simple consiste à copier toutes les informations FK dans une table simple à deux colonnes (parent, enfant), puis à utiliser l'algorithme suivant:

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

c'est tout. Fondamentalement, vous imprimez d'abord et supprimez tous les nœuds qui ne dépendent de rien. Cela fait, d’autres nœuds seront libres et vous pourrez répéter le processus.

P.S. Assurez-vous de ne pas insérer de tables auto-référencées dans la liste initiale (enfant = parent)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top