Listen Sie alle Sequenzen in einer Postgres-Datenbank 8.1 mit SQL auf

147

Ich konvertiere eine Datenbank von Postgres nach MySQL.

Da ich kein Tool finde, das den Trick selbst ausführt, werde ich alle Postgres-Sequenzen in Autoincrement-IDs in MySQL mit Autoincrement-Wert konvertieren.

Wie kann ich also alle Sequenzen in einer Postgres- Datenbank ( Version 8.1 ) mit Informationen zu der Tabelle, in der sie verwendet wird, dem nächsten Wert usw. mit einer SQL-Abfrage auflisten?

Beachten Sie, dass ich die information_schema.sequencesAnsicht in Version 8.4 nicht verwenden kann .

apelliciari
quelle
1
Es ist zu beachten, dass Sie die Konvertierung falsch durchführen. Seit Oracle Sun gekauft hat, haben sie MySQL langsam getötet. Wenn Sie Ihren Client nicht verachten (in diesem Fall sollten Sie einfach aufhören), sollten Sie sich an PostgreSQL halten, da kein Unternehmen (Pro-Monopol von nicht) mitkommen kann, PostgreSQL verschlingen und Ersetzen Sie es schließlich durch eine eigene Datenbank.
John
@ John Ich würde sagen, dass es eine Milliarde und einen weiteren Grund gibt, bei Postgres zu bleiben, und eine Milliarde mehr, um MySQL nie zu berühren, aber ja - Ihr Punkt ist immer noch sehr gültig :)
Ruslan
@ John zu der Zeit (2009) brauchen wir eine einfachere Datenbank, um damit umzugehen - und MySQL war besser an PHP gekoppelt
Apelliciari

Antworten:

250

Die folgende Abfrage gibt Namen aller Sequenzen an.

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

In der Regel wird eine Sequenz als benannt ${table}_id_seq. Durch den einfachen Abgleich von Regex-Mustern erhalten Sie den Tabellennamen.

Verwenden Sie die folgende Abfrage, um den letzten Wert einer Sequenz abzurufen:

SELECT last_value FROM test_id_seq;
Anand Chitipothu
quelle
5
Der ${table}_id_seqHinweis war nützlich
Pierre de LESPINAY
${table}_${column}_seqfür automatisch erstellte Sequenzen
Evgeny Nozdrev
80

Beachten Sie, dass Sie ab PostgreSQL 8.4 alle Informationen zu den in der Datenbank verwendeten Sequenzen erhalten können über:

SELECT * FROM information_schema.sequences;

Da ich eine höhere Version von PostgreSQL (9.1) verwende und nach derselben Antwort hoch und niedrig suchte, habe ich diese Antwort für die Nachwelt und für zukünftige Suchende hinzugefügt.

Raveren
quelle
1
Protip: Sortieren Sie die Antworten nach "aktiv". Die Nachwelt wird immer relevanter, da die Fragen immer
älter werden
1
Cool. Und es sieht so aus, als würde sich die Site sofort an die Einstellung erinnern, wenn ich die "aktive" Sortiermethode auswähle (hier habe ich mich in den Einstellungen umgesehen, um einen Ort zu finden, an dem sie als Standard ohne Erfolg festgelegt werden kann). Hm, jetzt , wenn nur wir hatten eine „Fragesteller-akzeptierte Antwort Trumpf alles nicht automatisch anders“ -Option, dass ein wirklich wäre großer Sieg für die Nachwelt.
Selten Needy
Beachten Sie, dass diese Tabelle in PG 8.4 eingeführt wurde. Ich würde PG 8.2 lieber nach der offiziellen Dokumentation sagen: postgresql.org/docs/8.2/infoschema-sequences.html
Guillaume Husta
Diese "alle Informationen" enthalten nicht den aktuellen Wert.
Bart
62

Führen Sie: psql -Eund dann aus\ds


quelle
1
Ich brauche nicht nur die Liste der Sequenzen, ich brauche die Tabelle, in der es verwendet wird, den nächsten Wert usw. Und ich muss das in SQL tun
apelliciari
Dann mache bei jeder Sequenz \ d <Name> (immer noch in psql -E)
Auch dies ist nicht in SQL und zeigt nicht an, an welcher Tabelle die Sequenz angehängt ist
apelliciari
@avastreg: hast du es so gemacht, wie ich es dir gesagt habe? und warum nicht?
10
@avastreg: JUST DO IT ONCE . Und es zeigt Ihnen die Fragen!
26

Nach ein bisschen Schmerz bekam ich es.

Der beste Weg, dies zu erreichen, besteht darin, alle Tabellen aufzulisten

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

Listen Sie dann für jede Tabelle alle Spalten mit Attributen auf

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

Testen Sie dann für jede Spalte, ob sie eine Sequenz hat

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

und erhalten Sie dann die Informationen zu dieser Sequenz

select * from <sequence_name>
apelliciari
quelle
13

Sequenzinfo: Maximalwert

SELECT * FROM information_schema.sequences;

Sequenzinfo: letzter Wert

SELECT * FROM <sequence_name>

bbh
quelle
11

Die Beziehung zwischen automatisch generierten Sequenzen (z. B. solchen, die für SERIAL-Spalten erstellt wurden) und der übergeordneten Tabelle wird durch das Sequenzbesitzerattribut modelliert.

Sie können diese Beziehung mit der OWNED BY-Klausel des Befehls ALTER SEQUENCE ändern

zB ALTER SEQUENCE foo_id OWNED von foo_schema.foo_table

um festzulegen, dass es mit der Tabelle foo_table verknüpft wird

oder ALTER SEQUENCE foo_id OWNED by NONE

um die Verbindung zwischen der Sequenz und einer beliebigen Tabelle zu unterbrechen

Die Informationen zu dieser Beziehung werden in der Katalogtabelle pg_depend gespeichert .

Die Verknüpfungsbeziehung ist die Verknüpfung zwischen pg_depend.objid -> pg_class.oid WHERE relkind = 'S' - die die Sequenz mit dem Verknüpfungsdatensatz verknüpft, und dann pg_depend.refobjid -> pg_class.oid WHERE relkind = 'r', die die verknüpft Datensatz mit der Eigentümerbeziehung verbinden (Tabelle)

Diese Abfrage gibt alle Sequenz-> Tabellenabhängigkeiten in einer Datenbank zurück. Die where-Klausel filtert es so, dass es nur automatisch generierte Beziehungen enthält, wodurch es darauf beschränkt wird, nur Sequenzen anzuzeigen, die von Spalten vom Typ SERIAL erstellt wurden.

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' ;
cms
quelle
Nützliche Erklärung der Abhängigkeiten zwischen Tabellen und Sequenzen. Aber Ihre Anfrage hat nicht alle Sequenzen für mich gefunden. Es scheint, dass einige Sequenzen ohne Abhängigkeiten existieren.
Evgeny Nozdrev
Ja, diese Abfrage zeigt explizit nur Sequenzen, die durch serielle Spaltendefinitionen der Datenbank definiert sind. Dies wird in der Antwort erklärt.
cms
5

Ich weiß, dass dieser Beitrag ziemlich alt ist, aber ich fand die Lösung von CMS sehr nützlich, da ich nach einer automatisierten Möglichkeit suchte, eine Sequenz mit der Tabelle AND-Spalte zu verknüpfen, und sie teilen wollte. Die Verwendung der Katalogtabelle pg_depend war der Schlüssel. Ich erweiterte, was getan wurde, um:

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' ;

Diese Version fügt der Liste der zurückgegebenen Felder eine Spalte hinzu. Durch den Aufruf von pg_set_serial_sequence können Sie mit dem Tabellennamen und dem Spaltennamen auf einfache Weise sicherstellen, dass alle Sequenzen in der Datenbank korrekt festgelegt sind. Beispielsweise:

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$;

Hoffe das hilft jemandem beim Zurücksetzen von Sequenzen!

DBAYoder
quelle
vor ein paar Jahren auf, merke ich das Update und Pop durch eine upvote zu geben :-)
cms
3

Diese Anweisung listet die Tabelle und Spalte auf, die jeder Sequenz zugeordnet sind:

Code:

    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'

mehr siehe hier Link zur Antwort


quelle
2

Verbesserung der vorherigen Antwort:

select string_agg('select sequence_name, last_value from ' || relname, chr(13) || 'union' || chr(13) order by relname) 
from pg_class where relkind ='S'
Alexander Ryabov
quelle
3
Bitte geben Sie Ihren Code nicht einfach ohne Erklärung ein. Da Sie angegeben haben, dass Ihr Code eine "Verbesserung der vorherigen Antwort" ist, sollten Sie uns auch mitteilen, WARUM es sich um eine Verbesserung handelt. Oh, gib nicht auf und willkommen bei SO!
Joel
Sollte ich eine Seite mit sinnlosem Text anstelle von präzisem Code (ein paar Zeilen) schreiben?
Alexander Ryabov
2
Das habe ich nie gesagt. Ich mag einfachen, präzisen Code. Wenn Sie jedoch angeben, dass Ihr Code eine Verbesserung darstellt, würden ein oder zwei Zeilen, in denen erklärt wird, WARUM es sich um eine Verbesserung handelt (bessere Lesbarkeit, verbesserte Leistung usw.), nicht schaden. Und Sie würden wahrscheinlich auch eine +1 von mir bekommen.
Joel
1

Teilweise getestet, sieht aber größtenteils vollständig aus.

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;

Guthaben, bei dem Guthaben fällig ist ... Es wurde teilweise aus dem SQL rückentwickelt, das von a \ d in einer bekannten Tabelle mit einer Sequenz protokolliert wurde. Ich bin sicher, es könnte auch sauberer sein, aber hey, Leistung war kein Problem.


quelle
1

Eine Art Hack, aber versuchen Sie Folgendes:

wähle 'wähle' '' || relname || '' 'als Sequenz, letzter_Wert von' || relname || 'union' FROM pg_catalog.pg_class c WHERE c.relkind IN ('S', '');

Entfernen Sie die letzte UNION und führen Sie das Ergebnis aus

jimbob
quelle
1

Rufen Sie Sequenzen für jede Spalte jeder Tabelle ab, indem Sie die DEFAULT-Klausel analysieren. Diese Methode liefert Informationen darüber, mit welchen Spaltensequenzen verknüpft ist, und verwendet keine Abhängigkeiten, die für einige Sequenzen möglicherweise nicht vorhanden sind. Auch die pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname)Funktion hat nicht alle Sequenzen für mich gefunden!

Lösung:

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;

Beachten Sie, dass 1 Sequenz in mehreren Tabellen verwendet werden kann, sodass sie hier in mehreren Zeilen aufgelistet werden kann.

Evgeny Nozdrev
quelle
0

Danke für Ihre Hilfe.

Hier ist die Funktion pl / pgsql, die jede Sequenz einer Datenbank aktualisiert.

---------------------------------------------------------------------------------------------------------
--- 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();
Tom Milon
quelle
0

Hier ist eine andere, die den Schemanamen neben dem Sequenznamen hat

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

Diese Funktion zeigt den letzten Wert jeder Sequenz an.

Es gibt eine 2-Spalten-Tabelle aus, die den Sequenznamen plus den zuletzt generierten Wert enthält.

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();
EIN V
quelle
0

Unter der Annahme exec(), dass in diesem Beitrag https://stackoverflow.com/a/46721603/653539 eine Funktion deklariert wurde , können Sequenzen zusammen mit ihren letzten Werten mit einer einzigen Abfrage abgerufen werden:

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
Tomáš Záluský
quelle
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;
Manuel
quelle
0

Hier ist ein Beispiel, wie psqlSie eine Liste aller Sequenzen mit ihren last_valuefolgenden Angaben abrufen können :

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

Spritzen
quelle