2010-03-24 4 views
17

J'ai une très grande base de données Oracle, avec beaucoup de nombreuses tables et des millions de lignes. J'ai besoin de supprimer l'un d'entre eux, mais je veux m'assurer que le laisser tomber ne cassera pas d'autres lignes dépendantes qui pointent vers lui comme un enregistrement de clé étrangère. Est-il possible d'obtenir une liste de tous les autres enregistrements, ou au moins des schémas de table, qui pointent vers cette ligne? Je sais que je pourrais juste essayer de le supprimer moi-même, et attraper l'exception, mais je ne vais pas exécuter le script moi-même et j'ai besoin de le faire fonctionner la première fois. J'ai les outils SQL Developer d'Oracle et PL/SQL Developer de AllRoundAutomations à ma disposition.Comment trouver les dépendances de clé étrangère pointant vers un enregistrement dans Oracle?

Merci d'avance!

+0

ne tentera pas de supprimer l'exception de lancement d'enregistrement référencé? – Andrey

+0

@Andrey oui ça va, mais j'en ai besoin pour courir sans lancer d'exception. – daveslab

Répondre

23

Je regarde toujours les touches étrangères pour la table de départ et retravaille. Les outils DB ont généralement un nœud de dépendances ou de contraintes. Je sais que L/SQL Developer est une façon de voir FK de, mais il a été un moment que je l'ai utilisé, donc je ne peux pas l'expliquer ...

avec XXXXXXXXXXXX il suffit de remplacer un nom de table ...

/* 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 
+1

le Sql est sensible à la casse – eschneider

+0

Pourriez-vous mettre cette requête en mode 'code', donc c'est un peu plus facile à lire? Sinon, je l'essaie maintenant. – daveslab

+0

Sélectionnez la partie de votre réponse avec le code SQL, puis appuyez sur ou appuyez sur le bouton pour la diriger directement vers la droite dans la barre d'outils de l'éditeur avec le guillemet comme symbole. Assurez-vous de le casser sur plusieurs lignes aussi. – daveslab

3

Nous pouvons utiliser le dictionnaire de données pour identifier les tables qui référencent la clé primaire de la table en question. A partir de ce que nous pouvons générer une dynamique SQL pour interroger les tables pour la valeur que nous voulons zapper:

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> 

Cet exemple triche un peu. Le nom de la clé primaire cible est codé en dur et la colonne référençant porte le même nom sur toutes les tables dépendantes. La résolution de ces problèmes est laissé comme un exercice pour le lecteur;)

23

Voici ma solution à la liste toutes les références à une table:

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' 
; 

Avec cette solution, vous avez également les informations dont la colonne dont la table fait référence à la colonne de votre table cible (et vous pouvez la filtrer).

5

J'ai eu un problème similaire récemment, mais j'ai vite fait de constater que trouver les dépendances directes n'est pas suffisant. J'ai donc écrit une requête pour afficher un arbre de dépendances clés étrangères à plusieurs niveaux:

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'; 

Il donne un résultat comme celui-ci, lors de l'utilisation EXPEDITION comme MYTABLE dans ma base de données:

SHIPMENT <-- ADDRESS 
SHIPMENT <-- PACKING_LIST 
    PACKING_LIST <-- PACKING_LIST_DETAILS 
    PACKING_LIST <-- PACKING_UNIT 
     PACKING_UNIT <-- PACKING_LIST_ITEM 
    PACKING_LIST <-- PO_PACKING_LIST 
... 
0

je fus surpris de voir comment Il était difficile de trouver l'ordre de dépendance des tables en fonction des relations de clés étrangères. J'en avais besoin parce que je voulais supprimer les données de toutes les tables et les importer à nouveau. Voici la requête que j'ai écrite pour lister les tables dans l'ordre des dépendances. J'ai été en mesure de scripter les suppressions en utilisant la requête ci-dessous, et d'importer à nouveau en utilisant les résultats de la requête dans l'ordre inverse.

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; 
0

Les contraintes Oracle utilisent des index de table pour référencer des données.
Pour savoir quelles tables référencent une table, recherchez simplement l'index dans l'ordre inverse.

/* 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 .: références Désactivation améliore considérablement le temps des commandes DML (mise à jour, supprimer et insérer).

Cela peut aider beaucoup dans les opérations de masse, où vous savez que toutes les données sont cohérentes.

/* 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; 
Questions connexes