web-dev-qa-db-fra.com

Répertorier toutes les séquences d'une base de données Postgres 8.1 avec SQL

Je convertis une base de données de postgres en mysql. 

Puisque je ne peux pas trouver un outil qui fait le tour lui-même, je vais convertir toutes les séquences postgres en identifiants auto-incrémentés dans mysql avec une valeur auto-incrémentée.

Alors, comment puis-je lister toutes les séquences dans Postgres DB ( 8.1 version) avec des informations sur la table dans laquelle elle est utilisée, la valeur suivante, etc. avec une requête SQL?

Sachez que je ne peux pas utiliser la vue information_schema.sequences dans la version 8.4.

113
apelliciari

La requête suivante donne les noms de toutes les séquences.

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

Généralement, une séquence est nommée ${table}_id_seq. La mise en correspondance de motif regex simple vous donnera le nom de la table.

Pour obtenir la dernière valeur d'une séquence, utilisez la requête suivante:

SELECT last_value FROM test_id_seq;
187
Anand Chitipothu

Notez qu'à partir de PostgreSQL 8.4, vous pouvez obtenir all des informations sur les séquences utilisées dans la base de données via:

SELECT * FROM information_schema.sequences;

Comme j'utilise une version supérieure de PostgreSQL (9.1) et que je cherchais la même réponse haute et basse, j'ai ajouté cette réponse pour le bien de la postérité et pour les futurs chercheurs.

50
raveren

Exécuter: psql -E, puis \ds

46
user80168

après un peu de douleur, je l'ai eu.

le meilleur moyen d'y parvenir est de lister toutes les tables

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

puis, pour chaque table, listez toutes les colonnes avec les attributs

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

puis, pour chaque colonne, testez si elle a une séquence

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

et ensuite, obtenir les informations sur cette séquence

select * from <sequence_name>
22
apelliciari

La relation entre les séquences générées automatiquement (telles que celles créées pour les colonnes SERIAL) et la table parent est modélisée par l'attribut propriétaire de la séquence. 

Vous pouvez modifier cette relation à l'aide de la clause OWNED BY de la commande ALTER SEQUENCE

par exemple. ALTER SEQUENCE foo_id OWNED par foo_schema.foo_table 

pour le lier à la table foo_table

ou ALTER SEQUENCE foo_id possédé par NONE

rompre la connexion entre la séquence et n'importe quelle table

Les informations sur cette relation sont stockées dans la table de catalogue pg_depend

la relation de jonction est le lien entre pg_depend.objid -> pg_class.oid WHERE relkind = 'S' - qui lie la séquence à l'enregistrement de jointure puis pg_depend.refobjid -> pg_class.oid WHERE relkind = 'r', qui relie rejoindre l'enregistrement à la relation propriétaire (table)

Cette requête renvoie toutes les dépendances de séquence -> de table dans une base de données. La clause where la filtre pour n'inclure que les relations générées automatiquement, ce qui la limite à afficher uniquement les séquences créées par des colonnes de type 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' ;
10
cms

information de séquence: valeur maximale

SELECT * FROM information_schema.sequences;

info de séquence: dernière valeur

SELECT * FROM <sequence_name>

8
bbh

Je sais que ce message est assez ancien, mais j'ai trouvé la solution de CMS très utile, car je cherchais un moyen automatisé de relier une séquence à la colonne table AND et je voulais partager. L'utilisation de pg_depend catalog table était la clé. J'ai étendu ce qui a été fait pour:

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

Cette version ajoute une colonne à la liste des champs retournés. Avec le nom de la table et le nom de la colonne en main, un appel à pg_set_serial_sequence permet de s’assurer facilement que toutes les séquences de la base de données sont définies correctement. Par exemple:

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

J'espère que cela aidera quelqu'un à réinitialiser des séquences!

2
DBAYoder

Amélioration de la réponse précédente:

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
Alexander Ryabov

Une sorte de bidouille, mais essayez ceci:

select 'select' '' || relname || '' 'en tant que séquence, last_value from' || relname || ' syndicat' FROM pg_catalog.pg_class c WHERE c.relkind IN ('S', '');

Supprimer le dernier UNION et exécuter le résultat

1
jimbob

Partiellement testé mais semble presque complet.

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;

Crédit lorsque le crédit est dû ... il est en partie inversé à partir du SQL enregistré depuis un\d sur une table connue qui avait une séquence. Je suis sûr que ça pourrait être plus propre aussi, mais bon, la performance n'était pas un problème.

1
joatmon

Merci de votre aide. 

Voici la fonction pl/pgsql qui met à jour chaque séquence d'une base de données.

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

En supposant que la fonction exec() soit déclarée dans cet article https://stackoverflow.com/a/46721603/653539 , les séquences ainsi que leurs dernières valeurs peuvent être extraites à l'aide d'une seule requête:

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
Tomáš Záluský

Voici un autre qui a le nom du schéma à côté du nom de la séquence

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

Obtenez des séquences pour chaque colonne de chaque table via l'analyse de la clause DEFAULT. Cette méthode fournit info sur les séquences de colonnes liées et n'utilise pas dependencies qui peut ne pas exister pour certaines séquences. Même la fonction pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname) a trouvé pas tous séquences pour moi!

Solution:

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;

Notez que 1 séquence peut être utilisée dans plusieurs tables, elle peut donc être répertoriée dans plusieurs lignes ici.

0
Evgeny Nozdrev

Cette instruction répertorie la table et la colonne associées à chaque séquence:

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'

plus voir ici lien pour répondre

0
user6606668

Cette fonction affiche la dernière valeur de chaque séquence.

Il génère un tableau à 2 colonnes indiquant le nom de la séquence et sa dernière valeur générée.

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