2008-09-17 19 views
4

J'essaie de créer un graphique de dépendances de tables basé sur les clés étrangères entre elles. Ce graphique doit commencer par un nom de table arbitraire en tant que racine. Je pourrais, au vu d'un nom de table, chercher les tables qui le référencent en utilisant la vue all_constraints, puis rechercher les tables qui les référencent, et ainsi de suite, mais ce serait horrible inefficace. J'ai écrit une requête récursive qui fait cela pour toutes les tables, mais quand j'ajoute:Construction d'un graphique de dépendance de table avec une requête récursive

START WITH Table_Name=:tablename 

Il ne retourne pas l'arbre entier.

Répondre

8
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 est dans le même schéma. Utilisez les versions DBA_ des tables et des conditions du dictionnaire de données pour les colonnes OWNER et R_OWNER si vous devez gérer les dépendances entre les schémas. À la réflexion, cela ne tient pas compte des contraintes auto-référentielles (c'est-à-dire une contrainte sur la table EMP que la colonne MGR référence la colonne EMPNO), donc vous devrez modifier le code pour gérer ce cas si vous avez besoin de traiter avec des contraintes autoréférentielles.

Pour des fins de test, j'ai ajouté quelques nouvelles tables au schéma SCOTT qui font référence aussi la table DEPT (y compris une dépendance 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 vérifié que la requête a retourné 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 
+0

Lorsque j'exécute cette requête, j'obtiens 'ORA-01437: ne peut pas avoir de jointure avec CONNECT BY' –

+0

@ user1598390 - Voulez-vous dire que lorsque vous exécutez le cas de test exact que j'ai signalé que vous obtenez une erreur? Ou faites-vous quelque chose (même légèrement) différent? Sans voir votre code, il est hautement improbable que nous puissions faire beaucoup pour vous aider. Vous allez probablement avoir besoin de créer une nouvelle question où vous pouvez publier la requête exacte que vous utilisez et, idéalement, l'afficher avec des exemples de tables que vous publiez. –

+0

Je copie votre SQL, le colle dans un client Oracle (PL/SQL Developer), puis appuie sur F8 pour l'exécuter et obtient l'erreur. –

2

Simplest façon de le faire est de copier toutes les informations FK en simple, 2 colonnes (parent, enfant) table, puis utilisez 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 

qui est tout. Fondamentalement, vous devez d'abord imprimer et supprimer tous les nœuds qui ne dépendent de rien. Après cela, d'autres nœuds seront libérés et vous pourrez répéter le processus.

P.S. Assurez-vous de ne pas insérer des tableaux d'auto-référencement dans la liste initiale (enfant = parent)