2009-09-29 6 views
82

Je convertis un db de postgres en mysql.Liste toutes les séquences dans un Postgres db 8.1 avec SQL

Comme je ne peux pas trouver un outil qui fait l'affaire elle-même, je vais convertir toutes les séquences de Postgres à auto-incrémentées ids dans une base MySQL avec une valeur autoincrement.

Alors, comment puis-je énumérer toutes les séquences dans un Postgres DB (8.1 Version) avec des informations sur la table où il est utilisé, la valeur suivante etc avec une requête SQL?

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

+1

Il convient de noter que vous faites la conversion dans le mauvais sens. Depuis qu'Oracle a acheté Sun, ils ont lentement détruit MySQL, donc à moins que vous ne méprisiez votre client (auquel cas vous devriez simplement quitter) vous devriez rester avec PostgreSQL car aucune société (pro-monopole de non) ne peut venir, avaler PostgreSQL et éventuellement le remplacer par leur propre base de données. – John

+0

@John Je dirais qu'il y a un milliard et une autre raison de rester avec postgres, et un milliard de plus pour ne jamais toucher mysql, mais oui - votre point est toujours très valable :) – Ruslan

+0

@John à l'époque (2009) nous avons besoin d'une base de données plus simple à traiter - et mysql était mieux couplé à php – apelliciari

Répondre

152

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

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

Habituellement, une séquence est nommée ${table}_id_seq. La correspondance simple du motif regex vous donnera le nom de la table.

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

SELECT last_value FROM test_id_seq; 
+5

L'indice '$ {table} _id_seq' était utile –

41

Run: psql -E, puis \ds

+1

je n'ai pas besoin seulement de la liste des séquences, j'ai besoin de la table dans laquelle il est utilisé, la valeur suivante etc .. Et je dois faire que dans SQL – apelliciari

+0

Ensuite, sur chaque séquence do \ d (étant toujours dans psql -E) –

+0

à nouveau, ce n'est pas en SQL et ne montre pas à quelle table la séquence est attachée – apelliciari

21

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

la meilleure façon d'y parvenir est de lister toutes les tables

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

puis, pour chaque table, liste toutes les colonnes avec des attributs

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

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

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

puis, obtenir des informations sur cette séquence

select * from <sequence_name> 
2

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 où le crédit est dû ... il est inverse en partie conçu à partir du SQL connecté à partir d'un \ d sur une table qui avait connu une séquence. Je suis sûr que ça pourrait aussi être plus propre, mais bon, la performance n'était pas un problème.

7

La relation entre les séquences générées automatiquement (tels que ceux qui sont créés pour les colonnes en série) et la table parent est modélisé par l'attribut de propriétaire de séquence.

Vous pouvez modifier cette relation à l'aide de la APPARTENANT clause du ALTER SEQUENCE commmand

par exemple ALTER SEQUENCE foo_id OWNED par foo_schema.foo_table

de le mettre à être relié à la table foo_table

ou SEQUENCE ALTER foo_id appartenant à NONE

pour rompre la liaison entre la séquence et une table

Les informations concernant cette relation est stocké dans le pg_depend catalogue table. La relation de jointure est le lien entre pg_depend.objid -> pg_class.oid O WH relkind = 'S' - qui relie la séquence à l'enregistrement de jointure puis pg_depend.refobjid -> pg_class.oid OERE relkind = 'r' , qui lie l'enregistrement de jointure à la relation propriétaire (table)

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

Une sorte de hack, mais essayez ceci:

sélectionnez 'select ''' || relname || '' 'comme séquence, last_value de' || relname || 'union' FROM pg_catalog.pg_class c O WH c.relkind IN ('S', '');

Retirez la dernière UNION et exécuter le résultat

0

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' 
+3

Veuillez ne pas mettre votre code sans aucune explication. Aussi, puisque vous avez déclaré que votre code est une "Amélioration de la réponse précédente", vous devez également nous dire POURQUOI c'est une amélioration. Oh, n'abandonnez pas, et bienvenue à SO! – Joel

+0

Dois-je écrire une page de texte insensé au lieu d'un code précis (deux lignes)? –

+1

Je n'ai jamais dit ça. J'aime le code simple et précis. Mais lorsque vous indiquez que votre code est une amélioration, une ou deux lignes expliquant pourquoi c'est une amélioration (meilleure lisibilité, performances améliorées, etc.) ne nuiraient pas. Et vous obtiendrez probablement un +1 de moi aussi. – Joel

32

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

SELECT * FROM information_schema.sequences; 

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

+1

J'espérais que quelqu'un penserait à la postérité quelque part ici dans les réponses ... +1 – SeldomNeedy

+1

Protip: trie les réponses par "actif". La postérité devient de plus en plus pertinente à mesure que les questions deviennent de plus en plus anciennes. – raveren

+1

Cool. Et il semble que si je choisis la méthode de tri "active", le site se souvient tout de suite du réglage (ici je cherchais des préférences pour trouver un endroit pour le définir par défaut en vain). Hm, maintenant si seulement nous avions une «réponse acceptée par le demandeur ne l'emportait pas automatiquement sur tout le reste» -option, * ce serait une véritable victoire pour la postérité. – SeldomNeedy

2

Je sais ce post est assez vieux, mais je trouve la solution par CMS est très utile que je cherchais un moyen automatisé de lier une séquence à la table et la colonne, et je voulais partager. L'utilisation de la table de catalogue pg_depend était la clé. J'élargi 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 la colonne à la liste des champs retournés. Avec le nom de la table et le nom de la colonne en main, un appel au pg_set_serial_sequence permet de s'assurer que toutes les séquences de la base de données sont correctement définies. 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$; 

Espérons que cela aide quelqu'un à réinitialiser les séquences!

0

Cette déclaration énumère la table et la colonne qui est associée à 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 link to answer

0

Merci pour 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(); 
3
informations de séquence

: valeur max

SELECT * FROM information_schema.sequences;

informations de séquence: dernière valeur

SELECT * FROM <sequence_name>

0

Voici un autre qui a le nom de 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 
Questions connexes