web-dev-qa-db-fra.com

SQL pour répertorier toutes les tables qui référencent une colonne particulière dans une table

J'utilise PostgreSQL et j'essaie de répertorier toutes les tables qui ont une colonne particulière d'une table comme clé étrangère/référence. Cela peut-il être fait? Je suis sûr que ces informations sont stockées quelque part dans information_schema mais je ne sais pas comment commencer à l'interroger.

50
Gaurav Dadhania
select R.TABLE_NAME
from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE u
inner join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS FK
    on U.CONSTRAINT_CATALOG = FK.UNIQUE_CONSTRAINT_CATALOG
    and U.CONSTRAINT_SCHEMA = FK.UNIQUE_CONSTRAINT_SCHEMA
    and U.CONSTRAINT_NAME = FK.UNIQUE_CONSTRAINT_NAME
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE R
    ON R.CONSTRAINT_CATALOG = FK.CONSTRAINT_CATALOG
    AND R.CONSTRAINT_SCHEMA = FK.CONSTRAINT_SCHEMA
    AND R.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
WHERE U.COLUMN_NAME = 'a'
  AND U.TABLE_CATALOG = 'b'
  AND U.TABLE_SCHEMA = 'c'
  AND U.TABLE_NAME = 'd'

Celui-ci utilise le triplet catalogue/schéma/nom complet pour identifier une table db à partir des 3 vues information_schema. Vous pouvez en déposer un ou deux au besoin.

La requête répertorie toutes les tables qui ont une contrainte de clé étrangère par rapport à la colonne "a" dans la table "d"

62
RichardTheKiwi

Les autres solutions ne sont pas garanties de fonctionner dans postgresql, car le nom_contrainte n'est pas garanti d'être unique; vous obtiendrez ainsi des faux positifs. PostgreSQL avait l'habitude de nommer des contraintes des choses idiotes comme '$ 1', et si vous avez une ancienne base de données que vous avez maintenue grâce à des mises à niveau, vous en avez probablement encore quelques-unes.

Puisque cette question était ciblée AT PostgreSQL et c'est ce que vous utilisez, vous pouvez alors interroger les tables internes postgres pg_class et pg_attribute pour obtenir un résultat plus précis.

REMARQUE: les FK peuvent être sur plusieurs colonnes, donc la colonne de référence (attnum de pg_attribute) est un ARRAY, ce qui est la raison pour laquelle array_agg est utilisé dans la réponse.

La seule chose dont vous avez besoin de vous connecter est le TARGET_TABLE_NAME:

select 
  (select r.relname from pg_class r where r.oid = c.conrelid) as table, 
  (select array_agg(attname) from pg_attribute 
   where attrelid = c.conrelid and ARRAY[attnum] <@ c.conkey) as col, 
  (select r.relname from pg_class r where r.oid = c.confrelid) as ftable 
from pg_constraint c 
where c.confrelid = (select oid from pg_class where relname = 'TARGET_TABLE_NAME');

Si vous voulez aller dans l'autre sens (listez toutes les choses auxquelles un tableau spécifique fait référence), changez simplement la dernière ligne en:

where c.conrelid = (select oid from pg_class where relname = 'TARGET_TABLE_NAME');

Oh, et puisque la question réelle était de cibler une colonne spécifique, vous pouvez spécifier le nom de la colonne avec celle-ci:

select (select r.relname from pg_class r where r.oid = c.conrelid) as table, 
       (select array_agg(attname) from pg_attribute 
        where attrelid = c.conrelid and ARRAY[attnum] <@ c.conkey) as col, 
       (select r.relname from pg_class r where r.oid = c.confrelid) as ftable 
from pg_constraint c 
where c.confrelid = (select oid from pg_class where relname = 'TARGET_TABLE_NAME') and 
      c.confkey @> (select array_agg(attnum) from pg_attribute 
                    where attname = 'TARGET_COLUMN_NAME' and attrelid = c.confrelid);
56
Tony K.

Personnellement, je préfère interroger en fonction de la contrainte unique référencée plutôt que de la colonne. Cela ressemblerait à quelque chose comme ceci:

SELECT rc.constraint_catalog,
       rc.constraint_schema||'.'||tc.table_name AS table_name,
       kcu.column_name,
       match_option,
       update_rule,
       delete_rule
FROM information_schema.referential_constraints AS rc 
    JOIN information_schema.table_constraints AS tc USING(constraint_catalog,constraint_schema,constraint_name)
    JOIN information_schema.key_column_usage AS kcu USING(constraint_catalog,constraint_schema,constraint_name)
WHERE unique_constraint_catalog='catalog'
    AND unique_constraint_schema='schema'
    AND unique_constraint_name='constraint name';

Voici une version qui permet d'interroger par nom de colonne:

SELECT rc.constraint_catalog,
       rc.constraint_schema||'.'||tc.table_name AS table_name,
       kcu.column_name,
       match_option,
       update_rule,
       delete_rule
FROM information_schema.referential_constraints AS rc
    JOIN information_schema.table_constraints AS tc USING(constraint_catalog,constraint_schema,constraint_name)
    JOIN information_schema.key_column_usage AS kcu USING(constraint_catalog,constraint_schema,constraint_name)
    JOIN information_schema.key_column_usage AS ccu ON(ccu.constraint_catalog=rc.unique_constraint_catalog AND ccu.constraint_schema=rc.unique_constraint_schema AND ccu.constraint_name=rc.unique_constraint_name)
WHERE ccu.table_catalog='catalog'
    AND ccu.table_schema='schema'
    AND ccu.table_name='name'
    AND ccu.column_name='column';
9
Anomie

Cette requête nécessite uniquement le nom de la table et le nom de la colonne, et produit un jeu de résultats contenant les deux côtés de la clé étrangère.

select confrelid::regclass, af.attname as fcol,
       conrelid::regclass, a.attname as col
from pg_attribute af, pg_attribute a,
  (select conrelid,confrelid,conkey[i] as conkey, confkey[i] as confkey
   from (select conrelid,confrelid,conkey,confkey,
                generate_series(1,array_upper(conkey,1)) as i
         from pg_constraint where contype = 'f') ss) ss2
where af.attnum = confkey and af.attrelid = confrelid and
      a.attnum = conkey and a.attrelid = conrelid 
  AND confrelid::regclass = 'my_table'::regclass AND af.attname = 'my_referenced_column';

Exemple de jeu de résultats:

confrelid |         fcol         |   conrelid    |     col
----------+----------------------+---------------+-------------
 my_table | my_referenced_column | some_relation | source_type
 my_table | my_referenced_column | some_feature  | source_type

Tout crédit à Lane et Krogh sur le forum PostgreSQL .

8
vallismortis
SELECT
  main_table.table_name            AS main_table_table_name,
  main_table.column_name           AS main_table_column_name,
  main_table.constraint_name       AS main_table_constraint_name,
  info_other_table.table_name      AS info_other_table_table_name,
  info_other_table.constraint_name AS info_other_table_constraint_name,
  info_other_table.column_name     AS info_other_table_column_name
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE main_table
  INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS other_table
    ON other_table.unique_constraint_name = main_table.constraint_name
  INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE info_other_table
    ON info_other_table.constraint_name = other_table.constraint_name
WHERE main_table.table_name = 'MAIN_TABLE_NAME';
4
Lucas

Une simple requête pour récupérer les noms de clé étrangère ainsi que les noms des tables:

SELECT CONSTRAINT_NAME, table_name
FROM
   information_schema.table_constraints 
WHERE table_schema='public' and constraint_type='FOREIGN KEY'
3
Fadid

Si vous utilisez le client psql , vous pouvez simplement émettre le \d table_name commande pour voir quelles tables référencent la table donnée. Depuis la page de documentation liée:

\d[S+] [ pattern ]

Pour chaque relation (table, vue, vue matérialisée, index, séquence ou table étrangère) ou type composite correspondant à pattern, affichez toutes les colonnes, leurs types, l'espace de table (si ce n'est pas la valeur par défaut) et tout attribut spécial tel que NOT NULL ou par défaut. Les index, contraintes, règles et déclencheurs associés sont également affichés. Pour les tables étrangères, le serveur étranger associé est également affiché.

0
Eugene Yarmash