Come posso determinare se una colonna è definita come un tipo di dati seriale anziché come numero intero basato sul catalogo?


9

Quindi attualmente sto creando alcuni SQL per leggere i cataloghi di Postgres (9.1) per creare definizioni di tabelle. Tuttavia, sto riscontrando un problema con i tipi di dati SERIAL / BIGSERIAL.

Esempio:

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"

Mi dà il nome del database (db), il nome dello schema (cruft), il nome della tabella (temp), il nome della colonna (id), il valore predefinito (nextval (...)) e il tipo di dati (bigint e int8 .. NOT bigserial) ... Mi rendo conto di poter semplicemente verificare se il valore predefinito era una sequenza, ma non credo che sarebbe accurato al 100% poiché potevo creare manualmente una sequenza e creare una colonna non seriale in cui il valore predefinito era quella sequenza.

Qualcuno ha un suggerimento su come potrei realizzare questo? Nient'altro che verificare il valore predefinito per un nextval (* _ seq)?

Modificato per la soluzione SQL aggiunta qui in caso di TL; DR o nuovi utenti che non hanno familiarità con il 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
Successivamente, risposta correlata con esempi di codice: dba.stackexchange.com/questions/90555/…
Erwin Brandstetter,

Risposte:


8

SERIAL e BIGSERIAL sono tipi di pseudo-tipi. Come hai notato, sono davvero solo INT e BIGINT internamente.

Quello che succede dietro le quinte è che PostgreSQL crea una sequenza e imposta una dipendenza da essa sul tavolo. Puoi cercare pg_class per il nome della sequenza e come si collega alla tabella.

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

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

Funzioni di sequenza: http://www.postgresql.org/docs/9.2/static/functions-sequence.html

Questo post StackOverflow potrebbe essere utile: /programming/1493262/list-all-sequences-in-a-postgres-db-8-1-with-sql

AGGIORNAMENTO : Puoi anche usare pg_depend per capire quali sequenze si riferiscono alla tabella / colonna che ti interessa: http://www.postgresql.org/docs/9.2/static/catalog-pg-depend.html


10

Consentitemi di aggiungere alla risposta di efesar che la documentazione afferma quanto segue:

I tipi di dati smallserial, serial e bigserial non sono tipi veri, ma semplicemente una comodità notazionale per la creazione di colonne identificative univoche (simile alla proprietà AUTO_INCREMENT supportata da altri database). Nell'attuale implementazione, specificando:

CREATE TABLE tablename (
    colname SERIAL
);

equivale a specificare:

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;

Ciò significa che se

  • il tipo di dati di una colonna è intero (bigint) e
  • non è NULL e
  • il suo valore predefinito deriva da una sequenza di proprietà della colonna in questione

allora è una serialcolonna. Pertanto, controllare questi fattori nei cataloghi, come proposto (con l'aggiunta di NOT NULL), è sufficiente per identificare una serialcolonna.

Per una vera query per trovare i (grandi) serial, vedere l' eccellente risposta di Erwin Brandstetter.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.