Comment déterminer si une colonne est définie comme un type de données série au lieu d'un entier basé sur le catalogue?

9

Je suis donc en train de créer du SQL pour lire les catalogues postgres (9.1) pour construire des définitions de table. Cependant, je rencontre un problème avec les types de données SERIAL / BIGSERIAL.

Exemple:

CREATE TABLE cruft.temp ( id BIGSERIAL PRIMARY KEY );
SELECT * FROM information_schema.columns WHERE table_schema='cruft' AND table_name='temp';
"db","cruft","temp","id",1,"nextval('cruft.temp_id_seq'::regclass)","NO","bigint",,,64,2,0,,,,,,,,,,,,,"db","pg_catalog","int8",,,,,"1","NO","NO",,,,,,,"NEVER",,"YES"

Il me donne le nom de la base de données (db), le nom du schéma (cruft), le nom de la table (temp), le nom de la colonne (id), la valeur par défaut (nextval (...)) et le type de données (bigint et int8 .. PAS bigserial) ... Je me rends compte que je pouvais simplement vérifier si la valeur par défaut était une séquence - mais je ne pense pas que ce serait précis à 100% car je pourrais créer manuellement une séquence et créer une colonne non série où la valeur par défaut était cette séquence.

Quelqu'un at-il une suggestion sur la façon dont je pourrais accomplir cela? Autre chose que de vérifier la valeur par défaut pour un nextval (* _ seq)?

Modifié pour la solution SQL ajoutée ici en cas de TL; DR ou de nouveaux utilisateurs peu familiers avec le pg_catalog:

with sequences as (
  select oid, relname as sequencename from pg_class where relkind = 'S'
) select
  sch.nspname as schemaname, tab.relname as tablename, col.attname as columnname, col.attnum as columnnumber, seqs.sequencename
from pg_attribute col
join pg_class tab on col.attrelid = tab.oid
join pg_namespace sch on tab.relnamespace = sch.oid
left join pg_attrdef def on tab.oid = def.adrelid and col.attnum = def.adnum
left join pg_depend deps on def.oid = deps.objid and deps.deptype = 'n'
left join sequences seqs on deps.refobjid = seqs.oid
where sch.nspname != 'information_schema' and sch.nspname not like 'pg_%' -- won't work if you have user schemas matching pg_
  and col.attnum > 0
  and seqs.sequencename is not null -- TO ONLY VIEW SERIAL/BIGSERIAL COLUMNS
order by sch.nspname, tab.relname, col.attnum;
Joishi Bodio
la source
1
Plus tard, réponse associée avec des exemples de code: dba.stackexchange.com/questions/90555/…
Erwin Brandstetter

Réponses:

8

SERIAL et BIGSERIAL sont des sortes de pseudo-types. Comme vous l'avez remarqué, ils ne sont vraiment que INT et BIGINT en interne.

Ce qui se passe dans les coulisses, c'est que PostgreSQL crée une séquence et configure une dépendance sur celle-ci à la table. Vous pouvez rechercher dans pg_class le nom de la séquence et sa relation avec la table.

pg_class: http://www.postgresql.org/docs/9.2/static/catalog-pg-class.html

SQL Fiddle: http://sqlfiddle.com/#!12/dfcbd/6

Fonctions de séquence: http://www.postgresql.org/docs/9.2/static/functions-sequence.html

Ce message StackOverflow peut être utile: /programming/1493262/list-all-sequences-in-a-postgres-db-8-1-with-sql

MISE À JOUR : Vous pouvez également utiliser pg_depend pour déterminer quelles séquences se rapportent à la table / colonne qui vous intéresse: http://www.postgresql.org/docs/9.2/static/catalog-pg-depend.html

efesar
la source
10

Permettez-moi d'ajouter à la réponse d'Efesar que la documentation indique ce qui suit:

Les types de données smallserial, serial et bigserial ne sont pas de vrais types, mais simplement une commodité de notation pour créer des colonnes d'identificateurs uniques (similaires à la propriété AUTO_INCREMENT prise en charge par certaines autres bases de données). Dans l'implémentation actuelle, spécifiant:

CREATE TABLE tablename (
    colname SERIAL
);

équivaut à spécifier:

CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
    colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;

Ce qui signifie que si

  • le type de données d'une colonne est un entier (bigint) et
  • ce n'est PAS NUL et
  • sa valeur par défaut provient d'une séquence appartenant à la colonne en question

alors c'est une serialcolonne. Il NOT NULLsuffit donc de vérifier ces facteurs dans les catalogues, comme vous l'avez proposé (avec l'ajout de ), pour identifier une serialcolonne.

Pour une requête réelle pour trouver les (grandes) séries, voir l' excellente réponse d'Erwin Brandstetter.

dezso
la source