2009-09-29 12 views
82

Sto convertendo un db da postgres in mysql.Elenca tutte le sequenze in un Postgre db 8.1 con SQL

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

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

Tenere presente che non è possibile utilizzare la vista information_schema.sequences nella versione 8.4.

+1

Va notato che stai facendo la conversione nel modo sbagliato. Dal momento che Oracle ha acquistato Sun, stanno lentamente uccidendo MySQL quindi, a meno che tu non disprezzi il tuo cliente (nel qual caso dovresti semplicemente smettere) dovresti seguire PostgreSQL perché nessuna società (pro-monopolio di no) può venire avanti, inghiottire PostgreSQL e eventualmente sostituirlo con il proprio database. – John

+0

@John Direi che c'è 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

+0

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

risposta

152

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 ${table}_id_seq. La semplice combinazione di espressioni regolari 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

L'suggerimento '$ {table} _id_seq' era utile –

41

Run: psql -E, e quindi \ds

+1

non ho bisogno solo dell'elenco delle sequenze, ho bisogno della tabella in cui è usato, del valore successivo ecc. E devo fare quello in SQL – apelliciari

+0

Quindi, su ogni sequenza \ d (essendo ancora in psql -E) –

+0

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

21

dopo un po 'di dolore, ho capito.

il modo migliore per ottenere questo è di elencare tutte le tabelle

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

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

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

quindi, per ogni colonna, prova se ha una sequenza

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

e poi, ottenere le informazioni su questa sequenza

select * from <sequence_name> 
2

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; 

di credito che è di Cesare ... è in parte decodificato dal SQL connesso da un \ d su un tavolo noto che ha avuto una sequenza. Sono sicuro che potrebbe anche essere più pulito, ma hey, le prestazioni non erano un problema.

7

Il rapporto tra sequenze generate automaticamente (come quelli creati per colonne serie) e la tabella padre è modellato dall'attributo proprietario sequenza.

È possibile modificare questo rapporto utilizzando la PROPRIETÀ DI clausola ALTER SEQUENCE commmand

esempio ALTER SEQUENCE foo_id OWNED di foo_schema.foo_table

impostare a essere collegata alla tabella foo_table

o ALTER SEQUENCE foo_id proprietà di NESSUNO

per interrompere il collegamento tra la sequenza e qualsiasi tabella

Le informazioni su questo rapporto è memorizzato nel pg_depend catalogue table.

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

Questa query restituisce tutte le dipendenze della sequenza -> tabella in un database. La clausola where la filtra per includere solo le relazioni generate automaticamente, che lo limitano a visualizzare solo le sequenze create dalle 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' ; 
0

una specie di hack, ma provate questo:

selezionare 'selezionare ''' || relname || '' 'come sequenza, last_value da' || relname || 'union' FROM pg_catalog.pg_class c WHERE c.relkind IN ('S', '');

Rimuovere l'ultimo UNION ed eseguire il risultato

0

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

Si prega di non inserire semplicemente il codice senza alcuna spiegazione. Inoltre, poiché hai affermato che il tuo codice è un "Miglioramento della risposta precedente", dovresti anche dirci PERCHÉ è un miglioramento. Oh, non arrenderti, e benvenuti a SO! – Joel

+0

Devo scrivere una pagina di testo senza senso invece di un codice preciso (un paio di righe)? –

+1

Mai detto questo. Mi piace il codice semplice e preciso. Ma quando affermi che il tuo codice è un miglioramento, una o due righe che spiegano perché è un miglioramento (migliore leggibilità, prestazioni migliorate, ecc.) Non farebbero male. E probabilmente avrai anche un +1 da me. – Joel

32

Nota, che a partire dal PostgreSQL 8.4 è possibile ottenere tutte informazioni su sequenze utilizzate nel database via:

SELECT * FROM information_schema.sequences; 

Dal momento che sto usando una versione più alta di PostgreSQL (9.1), e stavo cercando la stessa risposta in alto e in basso, ho aggiunto questa risposta per la posterità e per i futuri utenti.

+1

Speravo che qualcuno avrebbe pensato ai posteri da qualche parte qui sotto nelle risposte ... +1 – SeldomNeedy

+1

Protip: ordina le risposte con "attivo". I posteri diventano sempre più rilevanti in quanto le domande stanno diventando sempre più vecchie .. – raveren

+1

Cool. E sembra che se scelgo il metodo di ordinamento "attivo", il sito ricorda subito l'impostazione (qui stavo scavando nelle preferenze per trovare un posto dove impostarlo come predefinito senza alcun risultato). Hm, ora, se solo avessimo una "risposta accettata dal richiedente che non supera automaticamente tutto il resto" -option, * quella * sarebbe una vera vittoria per i posteri. – SeldomNeedy

2

So che questo post è piuttosto vecchio, ma ho trovato la soluzione di CMS molto utile in quanto cercavo un modo automatico per collegare una sequenza alla tabella E colonna e volevo condividere. L'uso della tabella di catalogo pg_depend era la chiave. Ho espanso l'effetto su:

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 il nome della tabella e il nome della colonna in mano, una chiamata a pg_set_serial_sequence rende facile assicurarsi che tutte le sequenze nel database siano impostate correttamente. Ad 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!

0

Questa dichiarazione elenca la tabella e la colonna che è associato con ogni 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 link to answer

0

Grazie per il vostro aiuto.

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

--------------------------------------------------------------------------------------------------------- 
--- 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(); 
3

sequenza: valore massimo

SELECT * FROM information_schema.sequences;

informazioni sequenza: ultimo valore

SELECT * FROM <sequence_name>

0

Ecco 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