Listar todas las secuencias en un Postgres db 8.1 con SQL


147

Estoy convirtiendo un db de postgres a mysql.

Como no puedo encontrar una herramienta que haga el truco en sí, voy a convertir todas las secuencias de postgres a identificadores de autoincremento en mysql con valor de autoincremento.

Entonces, ¿cómo puedo enumerar todas las secuencias en una base de datos Postgres DB ( versión 8.1 ) con información sobre la tabla en la que se usa, el siguiente valor, etc. con una consulta SQL?

Tenga en cuenta que no puedo usar la information_schema.sequencesvista en la versión 8.4.


1
Cabe señalar que está haciendo la conversión de manera incorrecta. Desde que Oracle compró Sun, han estado matando lentamente MySQL, por lo que, a menos que desprecia a su cliente (en cuyo caso simplemente debe renunciar), debe seguir con PostgreSQL ya que ninguna corporación (pro-monopolio de no) puede venir, engullir PostgreSQL y eventualmente reemplazarlo con su propia base de datos.
John

@John Diría que hay mil y una razones más para seguir con los postgres, y mil millones más para nunca tocar mysql, pero sí, su punto sigue siendo muy válido :)
Ruslan

@John at the time (2009) necesitamos una base de datos más simple para tratar, y mysql se
combinó

Respuestas:


251

La siguiente consulta proporciona nombres de todas las secuencias.

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

Por lo general, una secuencia se denomina como ${table}_id_seq. La simple coincidencia de patrones de expresiones regulares le dará el nombre de la tabla.

Para obtener el último valor de una secuencia, use la siguiente consulta:

SELECT last_value FROM test_id_seq;

55
La ${table}_id_seqsugerencia fue útil
Pierre de LESPINAY

${table}_${column}_seqpara secuencias creadas automáticamente
Evgeny Nozdrev

81

Tenga en cuenta que a partir de PostgreSQL 8.4 puede obtener toda la información sobre las secuencias utilizadas en la base de datos a través de:

SELECT * FROM information_schema.sequences;

Como estoy usando una versión superior de PostgreSQL (9.1), y estaba buscando la misma respuesta alta y baja, agregué esta respuesta por el bien de la posteridad y para futuros buscadores.


1
Protip: ordena las respuestas por "activo". La posteridad se vuelve más y más relevante que las preguntas son cada vez más vieja ..
raveren

1
Frio. Y parece que si elijo el método de clasificación "activo", el sitio solo recuerda la configuración de inmediato (aquí estaba cavando en las preferencias para encontrar un lugar para establecerlo como predeterminado en vano). Hm, ahora si sólo tenía una "respuesta-autor de la pregunta no aceptada automáticamente Trump todo lo demás" -opción, que sería verdaderamente una gran victoria para la posteridad.
SeldomNeedy

Tenga en cuenta que esta tabla se introdujo en PG 8.4, prefiero decir PG 8.2 después de la documentación oficial: postgresql.org/docs/8.2/infoschema-sequences.html
Guillaume Husta el

Esa "toda la información" no incluye el valor actual.
Bart

62

Ejecutar: psql -Ey luego\ds


1
No necesito sólo la lista de secuencias, necesito la tabla en la que se utiliza, el siguiente valor etc .. y tengo que hacer eso en SQL
apelliciari

Luego, en cada secuencia, haga \ d <nombre> (estando todavía en psql -E)

de nuevo, esto no está en SQL y no muestra en qué tabla se adjunta la secuencia
apelliciari

@avastreg: ¿lo ejecutaste como te dije? ¿y por qué no?

10
@avastreg: SOLO HAZLO UNA VEZ . ¡Y te mostrará las consultas!

26

Después de un poco de dolor, lo tengo.

la mejor manera de lograr esto es enumerar todas las tablas

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

y luego, para cada tabla, enumere todas las columnas con atributos

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

luego, para cada columna, pruebe si tiene una secuencia

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

y luego, obtener la información sobre esta secuencia

select * from <sequence_name>

13

información de secuencia: valor máximo

SELECT * FROM information_schema.sequences;

información de secuencia: último valor

SELECT * FROM <sequence_name>


11

El atributo propietario de la secuencia modela la relación entre las secuencias generadas automáticamente (como las creadas para las columnas SERIAL) y la tabla principal.

Puede modificar esta relación utilizando la cláusula OWNED BY del comando ALTER SEQUENCE

Ej. ALTERAR SECUENCIA foo_id PROPIETADO por foo_schema.foo_table

para que se vincule a la tabla foo_table

o ALTERAR SECUENCIA foo_id PROPIO por NINGUNO

para romper la conexión entre la secuencia y cualquier tabla

La información sobre esta relación se almacena en la tabla de catálogo pg_depend .

la relación de unión es el enlace entre pg_depend.objid -> pg_class.oid WHERE relkind = 'S' - que vincula la secuencia al registro de unión y luego pg_depend.refobjid -> pg_class.oid WHERE relkind = 'r', que vincula el unir registro a la relación propietaria (tabla)

Esta consulta devuelve todas las secuencias -> dependencias de la tabla en una base de datos. La cláusula where lo filtra para incluir solo relaciones generadas automáticamente, lo que lo restringe a mostrar solo secuencias creadas por columnas con tipo 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' ;

Explicación útil de dependencias entre tablas y secuencias. Pero su consulta no encontró todas las secuencias para mí. Parece que algunas secuencias existen sin ninguna dependencia.
Evgeny Nozdrev

Sí, esta consulta explícitamente solo muestra secuencias definidas por definiciones de columnas en serie de la base de datos. Esto se explica en la respuesta.
cms

5

Sé que esta publicación es bastante antigua, pero la solución de CMS me pareció muy útil, ya que estaba buscando una forma automatizada de vincular una secuencia a la tabla Y a la columna, y quería compartirla. El uso de la tabla de catálogo pg_depend fue la clave. Expandí lo que se hizo para:

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

Esta versión agrega columna a la lista de campos devueltos. Con el nombre de la tabla y el nombre de la columna en la mano, una llamada a pg_set_serial_sequence hace que sea fácil asegurarse de que todas las secuencias en la base de datos estén configuradas correctamente. Por ejemplo:

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

¡Espero que esto ayude a alguien a restablecer secuencias!


Unos años después, noté su actualización y apareció para dar un voto positivo :-)
cms

3

Esta declaración enumera la tabla y la columna que está asociada con cada secuencia:

Código:

    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'

más ver aquí enlace para responder


2

Mejora de la respuesta anterior:

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
Por favor, no solo ponga su código sin ninguna explicación. Además, dado que ha declarado que su código es una "Mejora de la respuesta anterior", también debe decirnos POR QUÉ es una mejora. ¡Oh, no te rindas y bienvenido a SO!
Joel

¿Debo escribir una página de texto sin sentido en lugar de código preciso (un par de líneas)?
Alexander Ryabov

2
Nunca dije eso. Me gusta el código simple y preciso. Pero al afirmar que su código es una mejora, una o dos líneas que explican POR QUÉ es una mejora (mejor legibilidad, mejor rendimiento, etc.) no afectarían. Y probablemente también obtendrás un +1 de mí.
Joel

1

Parcialmente probado pero parece mayormente 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;

Crédito donde se debe el crédito ... es en parte ingeniería inversa del SQL registrado desde a \ d en una tabla conocida que tenía una secuencia. Estoy seguro de que también podría estar más limpio, pero bueno, el rendimiento no era una preocupación.


1

Una especie de truco, pero prueba esto:

seleccione 'seleccionar' '' || relname || '' 'como secuencia, last_value de' || relname || 'union' DESDE pg_catalog.pg_class c DONDE c.relkind IN ('S', '');

Elimine la última UNIÓN y ejecute el resultado.


1

Obtenga secuencias por cada columna de cada tabla mediante el análisis de la cláusula DEFAULT. Este método proporciona información sobre qué secuencias de columnas están vinculadas y no utiliza dependencias que pueden no existir para algunas secuencias. ¡Incluso la pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname)función no encontró todas las secuencias para mí!

Solución:

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;

Tenga en cuenta que 1 secuencia se puede usar en varias tablas, por lo que se puede enumerar en varias filas aquí.


0

Gracias por tu ayuda.

Aquí está la función pl / pgsql que actualiza cada secuencia de una base de datos.

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

Aquí hay otro que tiene el nombre del esquema al lado del nombre de la secuencia

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

0

Esta función muestra el último valor de cada secuencia.

Produce una tabla de 2 columnas que dice el nombre de la secuencia más su último valor generado.

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

Asumiendo la exec()función declarada en esta publicación https://stackoverflow.com/a/46721603/653539 , las secuencias junto con sus últimos valores se pueden recuperar utilizando una sola consulta:

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

0

Aquí hay un ejemplo de cómo usar psqlpara obtener una lista de todas las secuencias con sus last_value:

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.