¿Cómo determino si una columna se define como un tipo de datos en serie en lugar de un entero basado en el catálogo?


9

Así que actualmente estoy creando algunos SQL para leer los catálogos de postgres (9.1) para construir definiciones de tabla. Sin embargo, me encuentro con un problema con los tipos de datos SERIAL / BIGSERIAL.

Ejemplo:

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"

Me da el nombre de la base de datos (db), el nombre del esquema (cruft), el nombre de la tabla (temp), el nombre de la columna (id), el valor predeterminado (nextval (...)) y el tipo de datos (bigint e int8 ... NO bigserial) ... Me doy cuenta de que podría verificar si el valor predeterminado era una secuencia, pero no creo que sea 100% preciso ya que podría crear manualmente una secuencia y crear una columna no serial donde el valor predeterminado era esa secuencia

¿Alguien tiene alguna sugerencia sobre cómo podría lograr esto? ¿Algo más que verificar el valor predeterminado para un nextval (* _ seq)?

Editado para la solución SQL agregada aquí en caso de TL; DR o nuevos usuarios que no están familiarizados con el 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;

1
Más tarde, respuesta relacionada con ejemplos de código: dba.stackexchange.com/questions/90555/…
Erwin Brandstetter

Respuestas:


8

SERIAL y BIGSERIAL son una especie de pseudo-tipos. Como notó, en realidad son solo INT y BIGINT internamente.

Lo que sucede detrás de escena es que PostgreSQL crea una secuencia y establece una dependencia en la tabla. Puede buscar pg_class para el nombre de secuencia y cómo se relaciona con la tabla.

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

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

Funciones de secuencia: http://www.postgresql.org/docs/9.2/static/functions-sequence.html

Esta publicación de StackOverflow puede ser útil: /programming/1493262/list-all-sequences-in-a-postgres-db-8-1-with-sql

ACTUALIZACIÓN : También puede usar pg_depend para averiguar qué secuencias se relacionan con la tabla / columna que le interesa: http://www.postgresql.org/docs/9.2/static/catalog-pg-depend.html


10

Permítanme agregar a la respuesta de efesar que la documentación establece lo siguiente:

Los tipos de datos smallserial, serial y bigserial no son tipos verdaderos, sino simplemente una conveniencia de notación para crear columnas de identificador único (similar a la propiedad AUTO_INCREMENT admitida por algunas otras bases de datos). En la implementación actual, especificando:

CREATE TABLE tablename (
    colname SERIAL
);

es equivalente a especificar:

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;

Lo que significa que si

  • El tipo de datos de una columna es entero (bigint) y
  • NO ES NULO y
  • su valor predeterminado proviene de una secuencia propiedad de la columna en cuestión

entonces es una serialcolumna. Por lo tanto, verificar estos factores en los catálogos, como propuso (con la adición de NOT NULL), es suficiente para identificar una serialcolumna.

Para una consulta real para encontrar las series (grandes), vea la excelente respuesta de Erwin Brandstetter.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.