330 votes

Comment lister les clés étrangères d'une table

Existe-t-il un moyen d'utiliser SQL pour lister toutes les clés étrangères pour une table donnée ? Je connais le nom de la table / le schéma et je peux l'introduire.

0 votes

Je suggère d'utiliser Réponse de @Magnus . Le plus simple, le plus propre, le plus rapide.

0 votes

@ErwinBrandstetter Cependant, la réponse acceptée donne directement les noms des colonnes et des tables, nous n'avons donc pas besoin de les analyser. Ce serait bien si la réponse de Magnus pouvait le faire aussi.

564voto

ollyc Points 691

Vous pouvez le faire via les tables information_schema. Par exemple :

SELECT
    tc.table_schema, 
    tc.constraint_name, 
    tc.table_name, 
    kcu.column_name, 
    ccu.table_schema AS foreign_table_schema,
    ccu.table_name AS foreign_table_name,
    ccu.column_name AS foreign_column_name 
FROM 
    information_schema.table_constraints AS tc 
    JOIN information_schema.key_column_usage AS kcu
      ON tc.constraint_name = kcu.constraint_name
      AND tc.table_schema = kcu.table_schema
    JOIN information_schema.constraint_column_usage AS ccu
      ON ccu.constraint_name = tc.constraint_name
      AND ccu.table_schema = tc.table_schema
WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name='mytable';

9 votes

Table_name='mytable' devrait être tc.table_name='mytable', sinon une erreur ambiguë sera générée.

21 votes

+1, très utile. Pour rendre la requête plus robuste, elle devrait probablement être jointe à la contrainte_schema également, puisqu'il est possible que deux schémas aient des contraintes avec le même nom. Quelque chose comme : FROM information_schema.table_constraints AS tc JOIN information_schema.key_column_usage AS kcu USING (constraint_schema, constraint_name) JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)

9 votes

Cela casse quand il y a plusieurs colonnes dans une contrainte, n'est-ce pas ? Il semble qu'il n'y ait pas de moyen approprié d'associer les colonnes pk aux colonnes fk en utilisant information_schema BTW.

87voto

Magnus Hagander Points 8671

Psql fait cela, et si vous démarrez psql avec :

psql -E

il vous montrera exactement quelle requête est exécutée. Dans le cas de la recherche de clés étrangères, c'est :

SELECT conname,
  pg_catalog.pg_get_constraintdef(r.oid, true) as condef
FROM pg_catalog.pg_constraint r
WHERE r.conrelid = '16485' AND r.contype = 'f' ORDER BY 1

Dans ce cas, 16485 est l'oid de la table que je regarde - vous pouvez l'obtenir en convertissant votre nom de table en regclass comme suit :

WHERE r.conrelid = 'mytable'::regclass

Qualifiez le nom de la table en fonction du schéma s'il n'est pas unique (ou s'il n'est pas le premier de la liste de votre search_path ) :

WHERE r.conrelid = 'myschema.mytable'::regclass

3 votes

C'est très pratique ! Postgres semble avoir un million de petites fonctions comme celle-ci qui rendent tout plus simple. Maintenant, comment s'en souvenir ?

6 votes

@Phil : Vous avez seulement besoin d'une idée générale. Laissez le manuel se souvenir du reste.

8 votes

Pour lister toutes les clés étrangères ciblant une table : SELECT conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef FROM pg_catalog.pg_constraint r WHERE r.confrelid = 'myschema.mytable'::regclass;

57voto

martin Points 1109

La réponse d'Ollyc est bonne car elle n'est pas spécifique à Postgres, cependant, elle s'effondre lorsque la clé étrangère fait référence à plus d'une colonne. La requête suivante fonctionne pour un nombre arbitraire de colonnes mais elle s'appuie fortement sur les extensions de Postgres :

select 
    att2.attname as "child_column", 
    cl.relname as "parent_table", 
    att.attname as "parent_column",
    conname
from
   (select 
        unnest(con1.conkey) as "parent", 
        unnest(con1.confkey) as "child", 
        con1.confrelid, 
        con1.conrelid,
        con1.conname
    from 
        pg_class cl
        join pg_namespace ns on cl.relnamespace = ns.oid
        join pg_constraint con1 on con1.conrelid = cl.oid
    where
        cl.relname = 'child_table'
        and ns.nspname = 'child_schema'
        and con1.contype = 'f'
   ) con
   join pg_attribute att on
       att.attrelid = con.confrelid and att.attnum = con.child
   join pg_class cl on
       cl.oid = con.confrelid
   join pg_attribute att2 on
       att2.attrelid = con.conrelid and att2.attnum = con.parent

0 votes

Avant 8.4, la fonction unnest doit être créée au départ. wiki.postgresql.org/wiki/Array_Unnest

0 votes

Où doit-on insérer le nom de la table dans cette requête ? Saisi textuellement, le résultat ci-dessus renvoie 0 ligne sur ma base de données PSQL qui comporte des dizaines de clés étrangères.

4 votes

Vous remplacez 'child_table' et 'child_schema' par les noms de la table et de son schéma.

38voto

Mvoicem Points 66

Extension à la recette ollyc :

CREATE VIEW foreign_keys_view AS
SELECT
    tc.table_name, kcu.column_name,
    ccu.table_name AS foreign_table_name,
    ccu.column_name AS foreign_column_name
FROM
    information_schema.table_constraints AS tc
    JOIN information_schema.key_column_usage 
        AS kcu ON tc.constraint_name = kcu.constraint_name
    JOIN information_schema.constraint_column_usage 
        AS ccu ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY';

Ensuite :

SELECT * FROM foreign_keys_view WHERE table_name='YourTableNameHere' ;

0 votes

Merci, idéal pour la réutilisation.

5voto

Guido García Points 13252

Vous pouvez utiliser le Catalogues système PostgreSQL . Vous pouvez peut-être demander pg_constraint pour demander des clés étrangères. Vous pouvez également utiliser la fonction Schéma d'information

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X