Postgres: SQL pour lister les clés étrangères de table

220

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

smack0007
la source
Je suggère d'utiliser la réponse de @Magnus . Le plus simple, le plus propre, le plus rapide.
Erwin Brandstetter

Réponses:

374

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';
ollyc
la source
8
table_name = 'mytable' devrait être tc.table_name = 'mytable', sinon il lance une erreur ambiguë
intrépide
15
+1, très utile. Pour rendre la requête plus robuste, elle devrait probablement se joindre également à constraint_schema, car 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)
EMP
8
Cela casse quand il y a plusieurs colonnes dans une contrainte, n'est-ce pas? Il ne semble pas y avoir de moyen approprié d'associer des colonnes pk à des colonnes fk en utilisant information_schema BTW.
fionbio
5
Il rompt en effet avec plus d'une colonne en contrainte. Pour Postgres, il existe un moyen d'obtenir ces informations à partir du schéma pg_catalog. Voir ma réponse ci-dessous.
martin
9
La requête est fausse. Il suppose que les noms de contraintes ne peuvent pas se répéter, ce qui est faux. Des contraintes portant le même nom peuvent exister dans différents espaces de noms. Vous utilisez nom_contrainte pour effectuer la jointure. La jointure à la fois sur nom_contrainte et nom de schéma ne fonctionnera pas car vous n'êtes pas sûr que les deux contraintes sont identiques. La seule option va pour pg_constraints, pg_class etc. utilisant oids pour se joindre. Le catalogue ANSI de Postgres n'est là que pour la conformité, mais il est imparfait. pg_catalog est le chemin à parcourir. La bonne réponse est ici dba.stackexchange.com/questions/36979/retrieving-all-pk-and-fk
Tulains Córdova
69

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 moulant simplement votre nom de table en regclass comme:

WHERE r.conrelid = 'mytable'::regclass

Qualifiez le nom du tableau s'il n'est pas unique (ou le premier de votre nom search_path):

WHERE r.conrelid = 'myschema.mytable'::regclass
Magnus Hagander
la source
2
C'est très pratique! Postgres semble avoir un million de petites fonctions comme celle-ci qui simplifient tout. Maintenant, comment s'en souvenir?
epic_fil
5
@Phil: Vous n'avez besoin que d'une idée générale. Laissez le manuel se souvenir du reste.
Erwin Brandstetter
3
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;
regilero
1
@ErwinBrandstetter comment faire pour obtenir un nom de table étranger?
Wellington Silva Ribeiro
2
Je ne comprends pas, quelle commande utiliser? psql -E -U username -d database ThenWHAT?
Poutrathor
49

Problème \d+ tablenamesur l'invite PostgreSQL, en plus d'afficher les types de données de la colonne de table, il affichera les index et les clés étrangères.

Gre Hahn
la source
Désolé, je n'ai pas remarqué que mon commentaire a été recadré. Si vous pouviez au moins l'essayer une fois, vous verriez que les mappages de clés étrangères sont également affichés.
Gre Hahn
45

La réponse d'Ollyc est bonne car elle n'est pas spécifique à Postgres, cependant, elle tombe en panne 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 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
Martin
la source
avant 8.4, la fonction unnest doit d'abord être créée. wiki.postgresql.org/wiki/Array_Unnest
maletin
Où insère-t-on le nom de la table dans cette requête? Entré textuellement, ce qui précède renvoie 0 lignes sur ma base de données PSQL qui a des dizaines de clés étrangères.
Phrogz
4
Vous remplacez 'child_table' et 'child_schema' par les noms de la table et de son schéma
martin
cela ne vous dit pas le nom de la touche f.
Evan Carroll du
@EvanCarroll J'ai mis à jour ma réponse pour inclure le nom de la clé.
martin
31

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

Mvoicem
la source
Merci, idéal pour la réutilisation.
schellingerht
16

consultez le post ff pour votre solution et n'oubliez pas de le marquer lorsque vous affinez cette utile

http://errorbank.blogspot.com/2011/03/list-all-foreign-keys-references-for.html

SELECT
  o.conname AS constraint_name,
  (SELECT nspname FROM pg_namespace WHERE oid=m.relnamespace) AS source_schema,
  m.relname AS source_table,
  (SELECT a.attname FROM pg_attribute a WHERE a.attrelid = m.oid AND a.attnum = o.conkey[1] AND a.attisdropped = false) AS source_column,
  (SELECT nspname FROM pg_namespace WHERE oid=f.relnamespace) AS target_schema,
  f.relname AS target_table,
  (SELECT a.attname FROM pg_attribute a WHERE a.attrelid = f.oid AND a.attnum = o.confkey[1] AND a.attisdropped = false) AS target_column
FROM
  pg_constraint o LEFT JOIN pg_class f ON f.oid = o.confrelid LEFT JOIN pg_class m ON m.oid = o.conrelid
WHERE
  o.contype = 'f' AND o.conrelid IN (SELECT oid FROM pg_class c WHERE c.relkind = 'r');
Sheldon
la source
Propose deux SQL qui fonctionnent sur PostgreSQL 9.1 (une fois que vous avez corrigé le mauvais échappement, mettez votre 'nom de table' (sans préfixe de schéma) dans le SQL).
alfonx
2
+1: c'est la seule solution qui ne renvoie pas de doublons.
Olivier MATROT
à cette solution, fonctionne très bien et ne renvoie pas de doublons.
Fuhrmann
1
Cette solution n'affichera que la première colonne de toutes les clés étrangères à plusieurs colonnes ... mais semble beaucoup plus simple que celle que je viens de publier et qui fera des multiples.
dewin
12

Cette requête fonctionne également correctement avec les clés composites:

select c.constraint_name
    , x.table_schema as schema_name
    , x.table_name
    , x.column_name
    , y.table_schema as foreign_schema_name
    , y.table_name as foreign_table_name
    , y.column_name as foreign_column_name
from information_schema.referential_constraints c
join information_schema.key_column_usage x
    on x.constraint_name = c.constraint_name
join information_schema.key_column_usage y
    on y.ordinal_position = x.position_in_unique_constraint
    and y.constraint_name = c.unique_constraint_name
order by c.constraint_name, x.ordinal_position
oscavi
la source
2
Vous rejoignez les colonnes sur "nom_contrainte", cela ne fonctionnera donc que si tous vos noms de contrainte sont uniques (dans toutes les tables de tous les schémas). Ce n'est généralement pas une exigence et n'est donc pas appliqué par la base de données.
Zilk
3
Merci. C'est la seule réponse qui montre comment utiliser information_schema pour gérer correctement plusieurs colonnes.
Samuel Danielson
Cette solution fonctionne. Il ne produit pas de doublons et gère plusieurs champs dans le FK.
Igor
9

Je pense que ce que vous cherchiez et très proche de ce que @ollyc a écrit est le suivant:

SELECT
tc.constraint_name, 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' AND ccu.table_name='YourTableNameHere';

Ceci listera toutes les tables qui utilisent votre table spécifiée comme clé étrangère

Shaun McCready
la source
9

vote positif court mais doux si cela fonctionne pour vous.

select  * from information_schema.key_column_usage where constraint_catalog=current_catalog and table_name='your_table_name' and position_in_unique_constraint notnull;
NikhilP
la source
A fonctionné un charme pendant que j'écris avec PG 12.2
Jack Kinsella
5

Aucune des réponses existantes ne m'a donné les résultats sous la forme dans laquelle je les souhaitais. Voici donc ma requête (gargantuesque) pour trouver des informations sur les clés étrangères.

Quelques notes:

  • Les expressions utilisées pour générer from_colset to_colspourraient être considérablement simplifiées sur Postgres 9.4 et WITH ORDINALITYversions ultérieures en utilisant plutôt que le piratage utilisant la fonction fenêtre que j'utilise.
  • Ces mêmes expressions reposent sur le planificateur de requêtes ne modifiant pas l'ordre retourné des résultats de UNNEST . Je ne pense pas que ce sera le cas, mais je n'ai pas de clés étrangères à plusieurs colonnes dans mon ensemble de données avec lesquelles tester. L'ajout des subtilités 9.4 élimine complètement cette possibilité.
  • La requête elle-même nécessite Postgres 9.0 ou version ultérieure (8.x ne permettait pas ORDER BYdans les fonctions d'agrégation)
  • Remplacez STRING_AGGpar ARRAY_AGGsi vous voulez un tableau de colonnes plutôt qu'une chaîne séparée par des virgules.

-

SELECT
    c.conname AS constraint_name,
    (SELECT n.nspname FROM pg_namespace AS n WHERE n.oid=c.connamespace) AS constraint_schema,

    tf.name AS from_table,
    (
        SELECT STRING_AGG(QUOTE_IDENT(a.attname), ', ' ORDER BY t.seq)
        FROM
            (
                SELECT
                    ROW_NUMBER() OVER (ROWS UNBOUNDED PRECEDING) AS seq,
                    attnum
                FROM
                    UNNEST(c.conkey) AS t(attnum)
            ) AS t
            INNER JOIN pg_attribute AS a ON a.attrelid=c.conrelid AND a.attnum=t.attnum
    ) AS from_cols,

    tt.name AS to_table,
    (
        SELECT STRING_AGG(QUOTE_IDENT(a.attname), ', ' ORDER BY t.seq)
        FROM
            (
                SELECT
                    ROW_NUMBER() OVER (ROWS UNBOUNDED PRECEDING) AS seq,
                    attnum
                FROM
                    UNNEST(c.confkey) AS t(attnum)
            ) AS t
            INNER JOIN pg_attribute AS a ON a.attrelid=c.confrelid AND a.attnum=t.attnum
    ) AS to_cols,

    CASE confupdtype WHEN 'r' THEN 'restrict' WHEN 'c' THEN 'cascade' WHEN 'n' THEN 'set null' WHEN 'd' THEN 'set default' WHEN 'a' THEN 'no action' ELSE NULL END AS on_update,
    CASE confdeltype WHEN 'r' THEN 'restrict' WHEN 'c' THEN 'cascade' WHEN 'n' THEN 'set null' WHEN 'd' THEN 'set default' WHEN 'a' THEN 'no action' ELSE NULL END AS on_delete,
    CASE confmatchtype::text WHEN 'f' THEN 'full' WHEN 'p' THEN 'partial' WHEN 'u' THEN 'simple' WHEN 's' THEN 'simple' ELSE NULL END AS match_type,  -- In earlier postgres docs, simple was 'u'nspecified, but current versions use 's'imple.  text cast is required.

    pg_catalog.pg_get_constraintdef(c.oid, true) as condef
FROM
    pg_catalog.pg_constraint AS c
    INNER JOIN (
        SELECT pg_class.oid, QUOTE_IDENT(pg_namespace.nspname) || '.' || QUOTE_IDENT(pg_class.relname) AS name
        FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid
    ) AS tf ON tf.oid=c.conrelid
    INNER JOIN (
        SELECT pg_class.oid, QUOTE_IDENT(pg_namespace.nspname) || '.' || QUOTE_IDENT(pg_class.relname) AS name
        FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid
    ) AS tt ON tt.oid=c.confrelid
WHERE c.contype = 'f' ORDER BY 1;
dewin
la source
5

Une autre façon:

WITH foreign_keys AS (
    SELECT
      conname,
      conrelid,
      confrelid,
      unnest(conkey)  AS conkey,
      unnest(confkey) AS confkey
    FROM pg_constraint
    WHERE contype = 'f' -- AND confrelid::regclass = 'your_table'::regclass
)
-- if confrelid, conname pair shows up more than once then it is multicolumn foreign key
SELECT fk.conname as constraint_name,
       fk.confrelid::regclass as referenced_table, af.attname as pkcol,
       fk.conrelid::regclass as referencing_table, a.attname as fkcol
FROM foreign_keys fk
JOIN pg_attribute af ON af.attnum = fk.confkey AND af.attrelid = fk.confrelid
JOIN pg_attribute a ON a.attnum = conkey AND a.attrelid = fk.conrelid
ORDER BY fk.confrelid, fk.conname
;
Konrad Perzyna
la source
4

Utilisez le nom de la clé primaire à laquelle les clés font référence et interrogez le schéma_information:

select table_name, column_name
from information_schema.key_column_usage
where constraint_name IN (select constraint_name
  from information_schema.referential_constraints 
  where unique_constraint_name = 'TABLE_NAME_pkey')

Ici, «TABLE_NAME_pkey» est le nom de la clé primaire référencée par les clés étrangères.

markmnl
la source
4

Voici une solution d'Andreas Joseph Krogh de la liste de diffusion PostgreSQL: http://www.postgresql.org/message-id/[email protected]

SELECT source_table::regclass, source_attr.attname AS source_column,
    target_table::regclass, target_attr.attname AS target_column
FROM pg_attribute target_attr, pg_attribute source_attr,
  (SELECT source_table, target_table, source_constraints[i] source_constraints, target_constraints[i] AS target_constraints
   FROM
     (SELECT conrelid as source_table, confrelid AS target_table, conkey AS source_constraints, confkey AS target_constraints,
       generate_series(1, array_upper(conkey, 1)) AS i
      FROM pg_constraint
      WHERE contype = 'f'
     ) query1
  ) query2
WHERE target_attr.attnum = target_constraints AND target_attr.attrelid = target_table AND
      source_attr.attnum = source_constraints AND source_attr.attrelid = source_table;

Cette solution gère les clés étrangères qui référencent plusieurs colonnes et évite les doublons (ce que certaines des autres réponses ne parviennent pas à faire). La seule chose que j'ai changé, ce sont les noms de variables.

Voici un exemple qui renvoie toutes les employeecolonnes qui référencent la permissiontable:

SELECT source_column
FROM foreign_keys
WHERE source_table = 'employee'::regclass AND target_table = 'permission'::regclass;
Gili
la source
4

Pour développer l'excellente réponse de Martin, voici une requête qui vous permet de filtrer en fonction de la table parent et vous montre le nom de la table enfant avec chaque table parent afin que vous puissiez voir toutes les tables / colonnes dépendantes en fonction des contraintes de clé étrangère dans la table parent.

select 
    con.constraint_name,
    att2.attname as "child_column", 
    cl.relname as "parent_table", 
    att.attname as "parent_column",
    con.child_table,
    con.child_schema
from
   (select 
        unnest(con1.conkey) as "parent", 
        unnest(con1.confkey) as "child", 
        con1.conname as constraint_name,
        con1.confrelid, 
        con1.conrelid,
        cl.relname as child_table,
        ns.nspname as child_schema
    from 
        pg_class cl
        join pg_namespace ns on cl.relnamespace = ns.oid
        join pg_constraint con1 on con1.conrelid = cl.oid
    where  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
   where cl.relname like '%parent_table%'       
Cervo
la source
1
La requête dans la réponse acceptée ajoute 1,2 seconde à une requête de ~ 0,03, la vôtre n'en ajoute que 0,01, merci!
AVProgrammer du
3

Solution appropriée au problème, en utilisant information_schema, en travaillant avec des clés multi-colonnes, en joignant correctement des colonnes de noms différents dans les deux tables et également compatible avec ms sqlsever:

select fks.TABLE_NAME as foreign_key_table_name
, fks.CONSTRAINT_NAME as foreign_key_constraint_name
, kcu_foreign.COLUMN_NAME as foreign_key_column_name
, rc.UNIQUE_CONSTRAINT_NAME as primary_key_constraint_name
, pks.TABLE_NAME as primary_key_table_name
, kcu_primary.COLUMN_NAME as primary_key_column_name
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS fks -- foreign keys
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu_foreign -- the columns of the above keys
    on fks.TABLE_CATALOG = kcu_foreign.TABLE_CATALOG
    and fks.TABLE_SCHEMA = kcu_foreign.TABLE_SCHEMA
    and fks.TABLE_NAME = kcu_foreign.TABLE_NAME
    and fks.CONSTRAINT_NAME = kcu_foreign.CONSTRAINT_NAME
inner join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc -- referenced constraints
    on rc.CONSTRAINT_CATALOG = fks.CONSTRAINT_CATALOG
    and rc.CONSTRAINT_SCHEMA = fks.CONSTRAINT_SCHEMA
    and rc.CONSTRAINT_NAME = fks.CONSTRAINT_NAME
inner join INFORMATION_SCHEMA.TABLE_CONSTRAINTS pks -- primary keys (referenced by fks)
    on rc.UNIQUE_CONSTRAINT_CATALOG = pks.CONSTRAINT_CATALOG
    and rc.UNIQUE_CONSTRAINT_SCHEMA = pks.CONSTRAINT_SCHEMA
    and rc.UNIQUE_CONSTRAINT_NAME = pks.CONSTRAINT_NAME
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu_primary
    on pks.TABLE_CATALOG = kcu_primary.TABLE_CATALOG
    and pks.TABLE_SCHEMA = kcu_primary.TABLE_SCHEMA
    and pks.TABLE_NAME = kcu_primary.TABLE_NAME
    and pks.CONSTRAINT_NAME = kcu_primary.CONSTRAINT_NAME
    and kcu_foreign.ORDINAL_POSITION = kcu_primary.ORDINAL_POSITION -- this joins the columns
where fks.TABLE_SCHEMA = 'dbo' -- replace with schema name
and fks.TABLE_NAME = 'your_table_name' -- replace with table name
and fks.CONSTRAINT_TYPE = 'FOREIGN KEY'
and pks.CONSTRAINT_TYPE = 'PRIMARY KEY'
order by fks.constraint_name, kcu_foreign.ORDINAL_POSITION

Remarque: Il existe certaines différences entre les implémentations potgresql et sqlserver, information_schemace qui fait que la première réponse donne des résultats différents sur les deux systèmes - l'un affiche les noms de colonne pour la table de clés étrangères, l'autre pour la table de clés primaires. Pour cette raison, j'ai décidé d'utiliser à la place la vue KEY_COLUMN_USAGE.

jakubiszon
la source
Le schéma d'information semble être la bonne réponse, mais vous voulez vraiment les tables pg_catalog: pg_constraint etc. Nous avons été durement mordus par cela. si votre base de données comporte de grandes quantités de contraintes, il peut y avoir des problèmes de performances ...
hajikelist
La condition ci-dessus activée ORDINAL_POSITIONpeut donner un résultat incorrect lorsque l'ordre des colonnes dans la clé étrangère est différent de l'ordre des colonnes dans la contrainte unique. Je pense que vous auriez dû vous joindre à la kcu_foreign.POSITION_IN_UNIQUE_CONSTRAINT = kcu_primary.ORDINAL_POSITION mise à jour : En outre, une clé étrangère peut également dépendre d'une contrainte UNIQUE, donc je pense que vous devriez supprimer la pks.CONSTRAINT_TYPEcondition et que vous pouvez simplement vous joindre rcà kcu_primarydirectement
easd
J'ai fait une réponse similaire ici: stackoverflow.com/a/62260908/9093051
easd
2
SELECT r.conname
      ,ct.table_name
      ,pg_catalog.pg_get_constraintdef(r.oid, true) as condef
  FROM pg_catalog.pg_constraint r, information_schema.constraint_table_usage ct
 WHERE r.contype = 'f' 
   AND r.conname = ct.constraint_name
 ORDER BY 1
Pugazendhi Asaimuthu
la source
2

J'ai écrit une solution qui aime et utilise fréquemment. Le code se trouve à http://code.google.com/p/pgutils/ . Voir la vue pgutils.foreign_keys.

Malheureusement, la sortie est trop verbeuse pour être incluse ici. Cependant, vous pouvez l'essayer sur une version publique de la base de données ici, comme ceci:

$ psql -h unison-db.org -U PUBLIC -d unison -c 'select * from pgutils.foreign_keys;

Cela fonctionne avec 8.3 au moins. Je prévois de le mettre à jour, si nécessaire, dans les prochains mois.

-Receece

Reece
la source
1
Le lien du projet est maintenant mort.
pimlottc
@pimlottc: déplacé vers bitbucket.org/reece/pgutils . Merci de l'avoir signalé.
Reece
0

Remarque: N'oubliez pas l'ordre des colonnes lors de la lecture des colonnes de contraintes!

SELECT conname, attname
  FROM pg_catalog.pg_constraint c 
  JOIN pg_catalog.pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = ANY (c.conkey)
 WHERE attrelid = 'schema.table_name'::regclass
 ORDER BY conname, array_position(c.conkey, a.attnum)
Nashev
la source
0

Voici ce que j'utilise actuellement, il listera une table et ses contraintes fkey [supprimer la clause table et listera toutes les tables du catalogue actuel]:

SELECT

    current_schema() AS "schema",
    current_catalog AS "database",
    "pg_constraint".conrelid::regclass::text AS "primary_table_name",
    "pg_constraint".confrelid::regclass::text AS "foreign_table_name",

    (
        string_to_array(
            (
                string_to_array(
                    pg_get_constraintdef("pg_constraint".oid),
                    '('
                )
            )[2],
            ')'
        )
    )[1] AS "foreign_column_name",

    "pg_constraint".conindid::regclass::text AS "constraint_name",

    TRIM((
        string_to_array(
            pg_get_constraintdef("pg_constraint".oid),
            '('
        )
    )[1]) AS "constraint_type",

    pg_get_constraintdef("pg_constraint".oid) AS "constraint_definition"

FROM pg_constraint AS "pg_constraint"

JOIN pg_namespace AS "pg_namespace" ON "pg_namespace".oid = "pg_constraint".connamespace

WHERE
    --fkey and pkey constraints
    "pg_constraint".contype IN ( 'f', 'p' )
    AND
    "pg_namespace".nspname = current_schema()
    AND
    "pg_constraint".conrelid::regclass::text IN ('whatever_table_name')
hajikelist
la source
0

le plus rapide à vérifier directement dans la réponse bash basée entièrement sur cette réponse

IFS='' read -r -d '' sql_code << EOF_SQL_CODE
      SELECT
      o.oid
      , o.conname AS constraint_name
      , (SELECT nspname FROM pg_namespace WHERE oid=m.relnamespace) AS source_schema
      , m.relname AS source_table
      , (SELECT a.attname FROM pg_attribute a
      WHERE a.attrelid = m.oid AND a.attnum = o.conkey[1] AND a.attisdropped = false) AS source_column
      , (SELECT nspname FROM pg_namespace
      WHERE oid=f.relnamespace) AS target_schema
      , f.relname AS target_table
      , (SELECT a.attname FROM pg_attribute a
      WHERE a.attrelid = f.oid AND a.attnum = o.confkey[1] AND a.attisdropped = false) AS target_column
      , ROW_NUMBER () OVER (ORDER BY o.oid) as rowid
      FROM pg_constraint o
      LEFT JOIN pg_class f ON f.oid = o.confrelid
      LEFT JOIN pg_class m ON m.oid = o.conrelid
      WHERE 1=1
      AND o.contype = 'f'
      AND o.conrelid IN (SELECT oid FROM pg_class c WHERE c.relkind = 'r')
EOF_SQL_CODE

psql -d my_db -c "$sql_code"
Yordan Georgiev
la source