it-swarm.com.de

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

Ich konvertiere eine Datenbank von Postgres in MySQL. 

Da ich kein Werkzeug finden kann, das den Trick selbst erledigt, konvertiere ich alle Postgres-Sequenzen in autoincrement-IDs in mysql mit autoincrement-Wert.

Wie kann ich also alle Sequenzen in einer Postgres DB ( 8.1 version) 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.sequences-Ansicht in Version 8.4 nicht verwenden kann.

113
apelliciari

Die folgende Abfrage gibt die Namen aller Sequenzen an.

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

Normalerweise wird eine Sequenz als ${table}_id_seq bezeichnet. Ein einfacher Regex-Musterabgleich gibt Ihnen den Tabellennamen.

Um den letzten Wert einer Sequenz zu erhalten, verwenden Sie die folgende Abfrage:

SELECT last_value FROM test_id_seq;
187

Beachten Sie, dass Sie ab PostgreSQL 8.4 all Informationen zu in der Datenbank verwendeten Sequenzen erhalten können:

SELECT * FROM information_schema.sequences;

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

50
raveren

Führen Sie aus: psql -E und dann \ds

46
user80168

nach ein bisschen schmerz bekam ich es.

dies erreichen Sie am besten, wenn Sie alle Tabellen auflisten

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

und dann für jede Tabelle alle Spalten mit Attributen auflisten

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>
22
apelliciari

Die Beziehung zwischen automatisch generierten Sequenzen (z. B. für SERIAL-Spalten erstellten Sequenzen) und der übergeordneten Tabelle wird durch das Sequence-Owner-Attribut modelliert. 

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

z.B. ALTER SEQUENCE foo_id BESITZT von foo_schema.foo_table 

um es mit der Tabelle foo_table zu verknüpfen

oder ALTER SEQUENCE foo_id VON KEINEM BENUTZT

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

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

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

Diese Abfrage gibt alle Sequenz-> Tabellenabhängigkeiten in einer Datenbank zurück. Die where-Klausel filtert sie so, dass sie nur automatisch generierte Beziehungen enthält. Dadurch werden nur Sequenzen angezeigt, die von SERIAL-Spalten 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' ;
10
cms

sequenzinfo: Maximalwert

SELECT * FROM information_schema.sequences;

sequenzinfo: letzter Wert

SELECT * FROM <sequence_name>

8
bbh

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

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 sowohl der Tabellenname als auch der Spaltenname auf einfache Weise sichergestellt werden, dass alle Sequenzen in der Datenbank richtig eingestellt sind. Zum Beispiel:

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!

2
DBAYoder

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

Irgendwie ein Hack, aber versuch das hier:

wählen Sie 'Auswählen' '' || relname || '' 'als Sequenz, letzter_Wert von' || relname || 'Vereinigung' FROM pg_catalog.pg_class c WO c.relkind IN ('S', '');

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

1
jimbob

Teilweise getestet, sieht aber meist 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-Protokoll eines\d in einer bekannten Tabelle mit einer Sequenz zurückentwickelt. Ich bin sicher, es könnte auch sauberer sein, aber hey, Leistung war kein Problem.

1
joatmon

Danke für Ihre Hilfe. 

Hier ist die pl/pgsql-Funktion, 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();
0
Tom Milon

Angenommen, die in diesem Beitrag deklarierte Funktion exec()https://stackoverflow.com/a/46721603/653539 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
0

Hier ist eine andere, deren Schemaname neben dem Sequenznamen steht

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

Rufen Sie Sequenzen für jede Spalte jeder Tabelle ab, indem Sie die DEFAULT-Klausel analysieren. Diese Methode liefert info darüber, welche Spaltensequenzen verknüpft sind und verwendet keine Abhängigkeiten , die für einige Sequenzen nicht vorhanden sind. Sogar 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 eine Sequenz in mehreren Tabellen verwendet werden kann, sodass sie hier in mehreren Zeilen aufgeführt werden kann.

0
Evgeny Nozdrev

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

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

0
user6606668

Diese Funktion zeigt den letzten Wert jeder Sequenz.

Es gibt eine 2-Spalten-Tabelle aus, die den Sequenznamen und den zuletzt generierten Wert angibt.

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
A_V