Elenca tutte le sequenze in un Postgres db 8.1 con SQL


147

Sto convertendo un db da postgres a mysql.

Dal momento che non riesco a trovare uno strumento che faccia il trucco stesso, ho intenzione di convertire tutte le sequenze di Postgres in ID di autoincremento in mysql con valore di autoincremento.

Quindi, come posso elencare tutte le sequenze in un DB Postgres ( versione 8.1 ) con le informazioni sulla tabella in cui viene utilizzato, il valore successivo, ecc. Con una query SQL?

Tieni presente che non riesco a utilizzare la information_schema.sequencesvista nella versione 8.4.


1
Va notato che stai facendo la conversione nel modo sbagliato. Da quando Oracle ha acquistato Sun, stanno lentamente uccidendo MySQL, quindi a meno che tu non disprezzi il tuo client (nel qual caso dovresti semplicemente smettere) dovresti rimanere con PostgreSQL poiché nessuna società (monopolio pro-monopolio) può arrivare, inghiottire PostgreSQL e eventualmente sostituirlo con il proprio database.
Giovanni

@Giovanni direi che ci sono un miliardo e un altro motivo per restare con postgres e un miliardo in più per non toccare mai mysql, ma sì - il tuo punto è ancora molto valido :)
Ruslan,

@John al momento (2009) abbiamo bisogno di un database più semplice da gestire - e mysql era meglio accoppiato a php
apelliciari

Risposte:


251

La seguente query fornisce i nomi di tutte le sequenze.

SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';

In genere una sequenza è denominata come ${table}_id_seq. La semplice corrispondenza del modello regex ti darà il nome della tabella.

Per ottenere l'ultimo valore di una sequenza, utilizzare la seguente query:

SELECT last_value FROM test_id_seq;

5
Il ${table}_id_seqsuggerimento è stato utile
Pierre de LESPINAY il

${table}_${column}_seqper sequenze create automaticamente
Evgeny Nozdrev,

81

Si noti che a partire da PostgreSQL 8.4 è possibile ottenere tutte le informazioni sulle sequenze utilizzate nel database tramite:

SELECT * FROM information_schema.sequences;

Dal momento che sto usando una versione successiva di PostgreSQL (9.1) e cercavo la stessa risposta alta e bassa, ho aggiunto questa risposta per il bene dei posteri e per i futuri ricercatori.


1
Protip: ordina le risposte per "attivo". I posteri diventano sempre più rilevanti man mano che le domande diventano sempre più vecchie ...
Raveren,

1
Freddo. E sembra che se scelgo il metodo di ordinamento "attivo", il sito ricorda immediatamente l'impostazione (qui stavo scavando nelle preferenze per trovare un posto per impostarlo come predefinito senza alcun risultato). Hm, ora se solo avessimo una "risposta richiedente ha accettato non automaticamente vincente tutto il resto" -opzione, che sarebbe un vero grande vittoria per i posteri.
SeldomNeedy,

Nota che questa tabella è stata introdotta in PG 8.4, preferirei dire PG 8.2 dopo la documentazione ufficiale: postgresql.org/docs/8.2/infoschema-sequences.html
Guillaume Husta

Quella "tutte le informazioni" non include il valore corrente.
Bart il

62

Esegui: psql -Ee quindi\ds


1
non ho bisogno solo dell'elenco delle sequenze, ho bisogno della tabella in cui viene utilizzato, il valore successivo ecc. E devo farlo in SQL
apelliciari,

Quindi, in ogni sequenza fai \ d <nome> (essendo ancora in psql -E)

di nuovo, questo non è in SQL e non mostra a quale tabella è allegata la sequenza
apelliciari

@avastreg: l'hai eseguito come ti avevo detto? e perchè no?

10
@avastreg: Just do it UNA VOLTA . E ti mostrerà le domande!

26

dopo un po 'di dolore, ho capito.

il modo migliore per raggiungere questo obiettivo è elencare tutte le tabelle

select * from pg_tables where schemaname = '<schema_name>'

e quindi, per ogni tabella, elenca tutte le colonne con attributi

select * from information_schema.columns where table_name = '<table_name>'

quindi, per ogni colonna, verifica se ha una sequenza

select pg_get_serial_sequence('<table_name>', '<column_name>')

e quindi ottenere le informazioni su questa sequenza

select * from <sequence_name>

13

info sequenza: valore massimo

SELECT * FROM information_schema.sequences;

info sequenza: ultimo valore

SELECT * FROM <sequence_name>


11

La relazione tra sequenze generate automaticamente (come quelle create per le colonne SERIAL) e la tabella padre è modellata dall'attributo proprietario della sequenza.

È possibile modificare questa relazione utilizzando la clausola OWNED BY del comando ALTER SEQUENCE

es. ALTER SEQUENCE foo_id PROPRIETARIO di foo_schema.foo_table

per impostarlo in modo che sia collegato alla tabella foo_table

o ALTER SEQUENCE foo_id PROPRIO da NESSUNO

per interrompere la connessione tra la sequenza e qualsiasi tabella

Le informazioni su questa relazione sono archiviate nella tabella del catalogo pg_depend .

la relazione di unione è il collegamento tra pg_depend.objid -> pg_class.oid WHERE relkind = 'S' - che collega la sequenza al record del join e quindi pg_depend.refobjid -> pg_class.oid WHERE relkind = 'r', che collega il unisci record alla relazione proprietaria (tabella)

Questa query restituisce tutte le sequenze -> dipendenze di tabelle in un database. La clausola where la filtra per includere solo le relazioni generate automaticamente, che le limita per visualizzare solo le sequenze create da colonne tipizzate SERIAL.

WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname , 
                           c.relkind, c.relname AS relation 
                    FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),

     sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),  
     tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )  
SELECT
       s.fqname AS sequence, 
       '->' as depends, 
       t.fqname AS table 
FROM 
     pg_depend d JOIN sequences s ON s.oid = d.objid  
                 JOIN tables t ON t.oid = d.refobjid  
WHERE 
     d.deptype = 'a' ;

Spiegazione utile delle dipendenze tra tabelle e sequenze. Ma la tua ricerca non ha trovato tutte le sequenze per me. Sembra che esistano alcune sequenze senza dipendenze.
Evgeny Nozdrev, il

Sì, questa query dimostra esplicitamente solo sequenze definite dalle definizioni delle colonne seriali del database. Questo è spiegato nella risposta.
cms

5

So che questo post è piuttosto vecchio, ma ho trovato la soluzione di CMS molto utile in quanto cercavo un modo automatizzato per collegare una sequenza alla tabella AND colonna e volevo condividere. L'uso della tabella del catalogo pg_depend era la chiave. Ho ampliato ciò che è stato fatto per:

WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,
                           c.relkind, c.relname AS relation
                    FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),

     sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
     tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
       s.fqname AS sequence,
       '->' as depends,
       t.fqname AS table,
       a.attname AS column
FROM
     pg_depend d JOIN sequences s ON s.oid = d.objid
                 JOIN tables t ON t.oid = d.refobjid
                 JOIN pg_attribute a ON a.attrelid = d.refobjid and a.attnum = d.refobjsubid
WHERE
     d.deptype = 'a' ;

Questa versione aggiunge colonna all'elenco dei campi restituiti. Con sia il nome della tabella che il nome della colonna in mano, una chiamata a pg_set_serial_sequence semplifica la corretta impostazione di tutte le sequenze nel database. Per esempio:

CREATE OR REPLACE FUNCTION public.reset_sequence(tablename text, columnname text)
 RETURNS void
 LANGUAGE plpgsql
AS $function$
DECLARE
    _sql VARCHAR := '';
BEGIN
    _sql := $$SELECT setval( pg_get_serial_sequence('$$ || tablename || $$', '$$ || columnname || $$'), (SELECT COALESCE(MAX($$ || columnname || $$),1) FROM $$ || tablename || $$), true)$$;
    EXECUTE _sql;
END;
$function$;

Spero che questo aiuti qualcuno con le sequenze di ripristino!


tra qualche anno, noto il tuo aggiornamento, e faccio un salto per dare un voto :-)
cms

3

Questa istruzione elenca la tabella e la colonna associate a ciascuna sequenza:

Codice:

    SELECT t.relname as related_table, 
           a.attname as related_column,
           s.relname as sequence_name
    FROM pg_class s 
      JOIN pg_depend d ON d.objid = s.oid 
      JOIN pg_class t ON d.objid = s.oid AND d.refobjid = t.oid 
      JOIN pg_attribute a ON (d.refobjid, d.refobjsubid) = (a.attrelid, a.attnum)
      JOIN pg_namespace n ON n.oid = s.relnamespace 
    WHERE s.relkind     = 'S' 

  AND n.nspname     = 'public'

più vedere qui il link per rispondere


2

Miglioramento della risposta precedente:

select string_agg('select sequence_name, last_value from ' || relname, chr(13) || 'union' || chr(13) order by relname) 
from pg_class where relkind ='S'

3
Per favore, non inserire semplicemente il tuo codice senza alcuna spiegazione. Inoltre, poiché hai dichiarato che il tuo codice è un "miglioramento della risposta precedente", dovresti anche dirci PERCHÉ è un miglioramento. Oh, non arrenderti e benvenuto in SO!
Joel

Dovrei scrivere una pagina di testo insensato anziché un codice preciso (un paio di righe)?
Alexander Ryabov,

2
Non l'ho mai detto. Mi piace un codice semplice e preciso. Ma quando si afferma che il codice è un miglioramento, una o due righe che spiegano PERCHÉ è un miglioramento (migliore leggibilità, miglioramento delle prestazioni, ecc.) Non farebbero male. E probabilmente otterrai anche un +1 da me.
Gioele

1

Parzialmente testato ma sembra per lo più completo.

select *
  from (select n.nspname,c.relname,
               (select substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
                  from pg_catalog.pg_attrdef d
                 where d.adrelid=a.attrelid
                   and d.adnum=a.attnum
                   and a.atthasdef) as def
          from pg_class c, pg_attribute a, pg_namespace n
         where c.relkind='r'
           and c.oid=a.attrelid
           and n.oid=c.relnamespace
           and a.atthasdef
           and a.atttypid=20) x
 where x.def ~ '^nextval'
 order by nspname,relname;

Credito dove è dovuto il credito ... è parzialmente invertito dal SQL registrato da un \ d su una tabella nota che aveva una sequenza. Sono sicuro che potrebbe essere anche più pulito, ma hey, le prestazioni non erano un problema.


1

Tipo di hack, ma prova questo:

seleziona 'seleziona' '' || relname || '' 'come sequenza, valore_ultimo da' || relname || 'union' FROM pg_catalog.pg_class c DOVE c.relkind IN ('S', '');

Rimuovere l'ultimo UNION ed eseguire il risultato


1

Ottieni sequenze per ogni colonna di ogni tabella tramite l'analisi della clausola DEFAULT. Questo metodo fornisce informazioni su quali sequenze di colonne sono collegate e non utilizza dipendenze che potrebbero non esistere per alcune sequenze. Anche la pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname)funzione non ha trovato tutte le sequenze per me!

Soluzione:

SELECT
    seq_sch.nspname  AS sequence_schema
  , seq.relname      AS sequence_name
  , seq_use."schema" AS used_in_schema
  , seq_use."table"  AS used_in_table
  , seq_use."column" AS used_in_column
FROM pg_class seq
  INNER JOIN pg_namespace seq_sch ON seq_sch.oid = seq.relnamespace
  LEFT JOIN (
              SELECT
                  sch.nspname AS "schema"
                , tbl.relname AS "table"
                , col.attname AS "column"
                , regexp_split_to_array(
                      TRIM(LEADING 'nextval(''' FROM
                           TRIM(TRAILING '''::regclass)' FROM
                                pg_get_expr(def.adbin, tbl.oid, TRUE)
                           )
                      )
                      , '\.'
                  )           AS column_sequence
              FROM pg_class tbl --the table
                INNER JOIN pg_namespace sch ON sch.oid = tbl.relnamespace
                --schema
                INNER JOIN pg_attribute col ON col.attrelid = tbl.oid
                --columns
                INNER JOIN pg_attrdef def ON (def.adrelid = tbl.oid AND def.adnum = col.attnum) --default values for columns
              WHERE tbl.relkind = 'r' --regular relations (tables) only
                    AND col.attnum > 0 --regular columns only
                    AND def.adsrc LIKE 'nextval(%)' --sequences only
            ) seq_use ON (seq_use.column_sequence [1] = seq_sch.nspname AND seq_use.column_sequence [2] = seq.relname)
WHERE seq.relkind = 'S' --sequences only
ORDER BY sequence_schema, sequence_name;

Si noti che 1 sequenza può essere utilizzata in più tabelle, quindi può essere elencata in più righe qui.


0

Grazie per l'aiuto.

Ecco la funzione pl / pgsql che aggiorna ogni sequenza di un database.

---------------------------------------------------------------------------------------------------------
--- Nom : reset_sequence
--- Description : Générique - met à jour les séquences au max de l'identifiant
---------------------------------------------------------------------------------------------------------

CREATE OR REPLACE FUNCTION reset_sequence() RETURNS void AS 
$BODY$
DECLARE _sql VARCHAR := '';
DECLARE result threecol%rowtype; 
BEGIN
FOR result IN 
WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,c.relkind, c.relname AS relation FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),
    sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
    tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
       s.fqname AS sequence,
       t.fqname AS table,
       a.attname AS column
FROM
     pg_depend d JOIN sequences s ON s.oid = d.objid
                 JOIN tables t ON t.oid = d.refobjid
                 JOIN pg_attribute a ON a.attrelid = d.refobjid and a.attnum = d.refobjsubid
WHERE
     d.deptype = 'a' 
LOOP
     EXECUTE 'SELECT setval('''||result.col1||''', COALESCE((SELECT MAX('||result.col3||')+1 FROM '||result.col2||'), 1), false);';
END LOOP;
END;$BODY$ LANGUAGE plpgsql;

SELECT * FROM reset_sequence();

0

Eccone un altro che ha il nome dello schema accanto al nome della sequenza

select nspname,relname from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = 'S' order by nspname

0

Questa funzione mostra l'ultimo valore di ciascuna sequenza.

Emette una tabella a 2 colonne che dice il nome della sequenza più il suo ultimo valore generato.

drop function if exists public.show_sequence_stats();
CREATE OR REPLACE FUNCTION public.show_sequence_stats()
    RETURNS TABLE(tablename text, last_value bigint) 
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE 
    ROWS 1000
AS $BODY$
declare r refcursor; rec record; dynamic_query varchar;
        BEGIN
            dynamic_query='select tablename,last_value from (';
            open r for execute 'select nspname,relname from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = ''S'' order by nspname'; 
            fetch next from r into rec;
            while found 
            loop
                dynamic_query=dynamic_query || 'select '''|| rec.nspname || '.' || rec.relname ||''' "tablename",last_value from ' || rec.nspname || '.' || rec.relname || ' union all ';
                fetch next from r into rec; 
            end loop;
            close r; 
            dynamic_query=rtrim(dynamic_query,'union all') || ') x order by last_value desc;';
            return query execute dynamic_query;
        END;
$BODY$;

select * from show_sequence_stats();

0

Supponendo che la exec()funzione dichiarata in questo post https://stackoverflow.com/a/46721603/653539 , le sequenze insieme ai loro ultimi valori possano essere recuperate utilizzando una singola query:

select s.sequence_schema, s.sequence_name,
  (select * from exec('select last_value from ' || s.sequence_schema || '.' || s.sequence_name) as e(lv bigint)) last_value
from information_schema.sequences s

0
select sequence_name, (xpath('/row/last_value/text()', xml_count))[1]::text::int as last_value
from (
    select sequence_schema,
            sequence_name,         
            query_to_xml(format('select last_value from %I.%I', sequence_schema, sequence_name), false, true, '') as xml_count
    from information_schema.sequences
    where sequence_schema = 'public'
) new_table order by last_value desc;

0

Ecco un esempio su come utilizzare psqlper ottenere un elenco di tutte le sequenze con le loro last_value:

psql -U <username> -d <database> -t -c "SELECT 'SELECT ''' || c.relname || ''' as sequence_name, last_value FROM ' || c.relname || ';' FROM pg_class c WHERE (c.relkind = 'S')" | psql -U <username> -d <database> -t

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.