Requête pour renvoyer les noms des colonnes de sortie et les types de données d'une requête, d'une table ou d'une vue


21

Existe-t-il une requête ou une commande PostgreSQL qui renvoie les noms de champs et les types de champs d'une requête, d'une table ou d'une vue?

Par exemple, une solution appliquée à une requête SELECT simple comme SELECT * from persondevrait renvoyer une liste comme:

Column Name   | Column Type
===========================
First Name    | character
Last Name     | character
Age           | integer
Date of Birth | date

J'ai recherché les information_schemavues décrites dans une réponse ci-dessous et cela semble assez bien couvrir les tableaux, et je soupçonne que cela couvre également les vues, mais je ne l'ai pas encore vérifié.

Le dernier est tout arbitraire , mais requête valide SELECT impliquant par exemple, JOINS, UNIONSetc., sur la base de données. Existe-t-il une procédure intégrée ou une autre procédure stockée ou un script qui peut renvoyer la même chose pour toute QUERY valide?

Je développe un programme qui crée des données et des formulaires de requête et les informations sont nécessaires pour la validation des données et l'exécution de fonctions sur les données retournées.


Il n'y a évidemment pas de "commande" unique, mais il existe différentes manières de récupérer des informations à partir des catalogues système. Veuillez poser une question spécifique , ajouter un exemple et ce que vous attendez en retour, et donnez-nous une idée de l'intention derrière cela.
Erwin Brandstetter

1
La raison de la simplicité est qu'en ce qui concerne les clients, les requêtes c'est-à-dire les SELECTrequêtes, c'est-à- dire les requêtes ne définissant pas ou manipulant les données, que ce soit sur des tables, des vues ou d'autres requêtes, retournent des lignes et des colonnes de données, donc PostgreSQL devrait pouvoir renvoyer un liste des noms de colonnes et de leurs types de données. Les information_schemavues mentionnées ci-dessous dans les réponses semblent y répondre pour les tableaux et les vues. Les requêtes SELECT arbitraires constituent la dernière frontière. Je vais modifier la réponse pour mieux expliquer
vfclists

Réponses:


22

Schéma d'information vs catalogues système

Nous avons eu des discussions à ce sujet à plusieurs reprises. Le schéma d'information sert à certaines fins. Si vous connaissez votre chemin dans les catalogues système, ceux-ci servent mieux la plupart des objectifs , l'OMI. Les catalogues système sont la véritable source de toutes les informations.

Le schéma d'information fournit des vues standardisées qui facilitent la portabilité, principalement sur les principales versions de Postgres, car la portabilité sur différentes plates-formes SGBDR est généralement une illusion une fois que vos requêtes sont suffisamment sophistiquées pour avoir besoin de rechercher des catalogues système. Et, notamment, Oracle ne prend toujours pas en charge le schéma d'informations.

Les vues dans le schéma d'informations doivent parcourir plusieurs cercles pour obtenir un format conforme à la norme. Cela les rend lents, parfois très lents. Comparez les plans et les performances de ces objets de base:

EXPLAIN ANALYZE SELECT * from information_schema.columns;
EXPLAIN ANALYZE SELECT * from pg_catalog.pg_attribute;

La différence est remarquable. Cela dépend vraiment de ce que vous recherchez.

Votre exemple

Pour votre exemple SELECT * from tbl, comparez les deux requêtes ci-dessous pour ce tableau simple:

CREATE TEMP TABLE foo(
   A numeric(12,3)
 , b timestamp(0)
);

En utilisant pg_attribute:

SELECT attname, format_type(atttypid, atttypmod) AS type
FROM   pg_attribute
WHERE  attrelid = 'foo'::regclass
AND    attnum > 0
AND    NOT attisdropped
ORDER  BY attnum;

format_type() renvoie le type complet avec tous les modificateurs:

attname | type
--------+-------------------------------
a       | numeric(12,3)
b       | timestamp(0) without time zone

Notez également que le transtypage regclassrésout le nom de la table de manière quelque peu intelligente en fonction du courant search_path. Il déclenche également une exception si le nom n'est pas valide. Détails:

En utilisant information_schema.columns:

SELECT column_name, data_type
FROM   information_schema.columns
WHERE  table_name = 'foo'
ORDER  BY ordinal_position;

Les informations sont standardisées mais incomplètes :

column_name | data_type
------------+----------------------------
a           | numeric
b           | timestamp without time zone

Pour obtenir des informations complètes sur le type de données, vous devez également prendre en compte toutes ces colonnes:

character_maximum_length
character_octet_length
numeric_precision
numeric_precision_radix
numeric_scale
datetime_precision
interval_type
interval_precision

Réponses associées:

Une liste des avantages et des inconvénients , les plus grands avantages (OMI) en gras:

Vues du schéma d'information

  • souvent plus simple (dépend)
  • lent
  • prétraité, qui peut ou non convenir à vos besoins
  • sélectif (les utilisateurs ne voient que les objets pour lesquels ils ont des privilèges)
  • conforme à une norme SQL (qui est implémentée par certains des principaux SGBDR)
  • principalement portable sur les principales versions de Postgres
  • ne nécessitent pas beaucoup de connaissances spécifiques sur Postgres
  • les identifiants sont descriptifs, longs et parfois maladroits

Catalogues système

  • souvent plus complexe (dépend), plus proche de la source
  • vite
  • complète (colonnes système commeoid incluses)
  • ne se conforme pas à une norme SQL
  • moins portable sur les principales versions de Postgres (mais les bases ne vont pas changer)
  • nécessitent des connaissances plus spécifiques sur Postgres
  • les identifiants sont concis, moins descriptifs mais commodément courts

Requête arbitraire

Pour obtenir la même liste de noms et types de colonnes à partir d'une requête, vous pouvez utiliser une astuce simple: CRÉER une table temporaire à partir de la sortie de la requête, puis utiliser les mêmes techniques que ci-dessus.

Vous pouvez ajouter LIMIT 0, car vous n'avez pas besoin de données réelles:

CREATE TEMP TABLE tmp123 AS
SELECT 1::numeric, now()
LIMIT  0;

Pour obtenir le type de données de colonnes individuelles, vous pouvez également utiliser la fonction pg_typeof():

SELECT pg_typeof(1);

Merci beaucoup. J'ai cherché comment obtenir le type de données de la colonne dans pg_attribute pendant un certain temps et je suis juste tombé sur ce message. Appréciez votre message.
Melinda

Cela est utile en général, mais ne répond pas à la question d'origine sur la façon d'obtenir des informations sur les types de données des colonnes fournies par une instruction SELECT. Il ne s'agissait pas des colonnes de vues ou de tables, qui bien sûr résident dans les catalogues système et sont également affichées dans le schéma d'information.
Holger Jakobs


2

Si vous avez accès au pg_catalog et utilisez PgAdmin3, je recommande fortement une solution que j'ai trouvée sur le blog de Valentine's Tech ( http://tech.valgog.com/2011/02/pgadmin-iii-macros-get-table-fields. html ). Il s'agit d'une macro PgAdmin3 accessible avec un raccourci pour afficher la définition d'un nom de table sélectionné.

select quote_ident(nspname) || '.' || quote_ident(relname) as table_name, 
       quote_ident(attname) as field_name, 
       format_type(atttypid,atttypmod) as field_type, 
       case when attnotnull then ' NOT NULL' else '' end as null_constraint,
       case when atthasdef then 'DEFAULT ' || 
                                ( select pg_get_expr(adbin, attrelid) 
                                    from pg_attrdef 
                                   where adrelid = attrelid and adnum = attnum )::text else ''
       end as dafault_value,
       case when nullif(confrelid, 0) is not null
            then confrelid::regclass::text || '( ' || 
                 array_to_string( ARRAY( select quote_ident( fa.attname ) 
                                           from pg_attribute as fa 
                                          where fa.attnum = ANY ( confkey ) 
                                            and fa.attrelid = confrelid
                                          order by fa.attnum 
                                        ), ','
                                 ) || ' )'
            else '' end as references_to
  from pg_attribute 
       left outer join pg_constraint on conrelid = attrelid 
                                    and attnum = conkey[1] 
                                    and array_upper( conkey, 1 ) = 1,
       pg_class, 
       pg_namespace
 where pg_class.oid = attrelid
   and pg_namespace.oid = relnamespace
   and pg_class.oid = btrim( '$SELECTION$' )::regclass::oid
   and attnum > 0
   and not attisdropped
 order by attrelid, attnum;

Fonctionne comme un charme et extrêmement utile.


1

Utilisez les information_schemavues , elles sont standard SQL et contiennent les informations que vous souhaitez.

Vous pouvez également accéder directement pg_class, pg_attributeetc., mais c'est souvent fiddlier et non portable; vous devrez peut-être des fonctions d'aide commeoidvectortypes ,pg_get_function_arguments , etc pour certaines choses.

Si vous voulez voir comment psqlexécute quelque chose comme \dt, exécutez psql -E- cela imprimera la requête. Cependant, il est généralement préférable d'utiliser le information_schemasi cela répond à vos besoins.


1

Cela peut être trop simple, mais pgAdmin4 affiche les types de champs dans les résultats de sortie. Les autres solutions ci-dessus sont probablement plus élégantes, mais lorsque j'ai juste besoin d'une réponse rapide, je trouve que l'interface graphique de requête de pgAdmin4 fonctionne plutôt bien. Essayer de comprendre le type de champ d'un champ calculé renvoyé par une vue ou une fonction peut être délicat.

entrez la description de l'image ici


C'est très agréable que pgAdmin4 fasse cela, mais comment cela se fait-il? Peut-on découvrir sans parcourir tout le code source de PgAdmin4?
Holger Jakobs
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.