Listar todas as sequências em um Postgres db 8.1 com SQL


147

Estou convertendo um db do postgres para mysql.

Como não consigo encontrar uma ferramenta que faça o truque, vou converter todas as seqüências do postgres em IDs de autoincremento no mysql com o valor de autoincrement.

Então, como posso listar todas as seqüências em um banco de dados do Postgres ( versão 8.1 ) com informações sobre a tabela em que ele é usado, o próximo valor etc com uma consulta SQL?

Esteja ciente de que não posso usar a information_schema.sequencesexibição na versão 8.4.


1
Observe que você está fazendo a conversão da maneira errada. Como a Oracle comprou a Sun, eles estão lentamente matando o MySQL; portanto, a menos que você despreze seu cliente (nesse caso, você deve simplesmente desistir), você deve seguir o PostgreSQL, pois nenhuma empresa (pró-monopólio de não) pode aparecer, devore o PostgreSQL e eventualmente substitua-o por seu próprio banco de dados.
— John

@ John Eu diria que há um bilhão e uma outras razões para ficar com postgres, e um bilhão a mais para mysql Nunca toque, mas sim - seu ponto ainda é muito válido :)
— Ruslan

@ John na época (2009), precisamos de uma base de dados mais simples para lidar com - e mysql foi melhor acoplado a php
— apelliciari

Respostas:


251

A consulta a seguir fornece nomes de todas as seqüências.

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

Normalmente, uma sequência é nomeada como ${table}_id_seq. A correspondência simples de padrão de regex fornecerá o nome da tabela.

Para obter o último valor de uma sequência, use a seguinte consulta:

SELECT last_value FROM test_id_seq;

5
A ${table}_id_seqdica foi útil
— Pierre de LESPINAY

${table}_${column}_seqpara seqüências criadas automaticamente
— Evgeny Nozdrev

80

Observe que, a partir do PostgreSQL 8.4, você pode obter todas as informações sobre sequências usadas no banco de dados via:

SELECT * FROM information_schema.sequences;

Como estou usando uma versão mais alta do PostgreSQL (9.1) e estava procurando a mesma resposta, alta e baixa, adicionei essa resposta para bem da posteridade e para futuros pesquisadores.


1
Protip: classifique as respostas por "ativo". Posteridade fica cada vez mais relevante como perguntas estão se tornando cada vez mais velha ..
— raveren

1
Legal. E parece que se eu escolher o método de classificação "ativo", o site se lembrará da configuração imediatamente (aqui eu estava pesquisando nas preferências para encontrar um lugar para defini-la como padrão sem sucesso). Agora, se tivéssemos uma opção "resposta aceita pelo autor da pergunta não supera automaticamente todo o resto" - essa seria uma vitória verdadeiramente grande para a posteridade.
— SeldomNeedy

Observe que esta tabela foi introduzida na PG 8.4, prefiro a PG 8.2 após a documentação oficial: postgresql.org/docs/8.2/infoschema-sequences.html
— Guillaume Husta

Que "todas as informações" não inclui o valor atual.
— Bart

62

Executar: psql -Ee depois\ds


1
eu não preciso apenas a lista de seqüências, eu preciso da mesa em que ele é usado, o valor seguinte etc .. E eu tenho que fazer isso em SQL
— apelliciari

Então, em cada seqüência do \ d <name> (sendo ainda no psql -E)

Novamente, isto não está em SQL e não mostra em qual tabela a seqüência é anexado
— apelliciari

@avastreg: você executou da maneira que eu disse? e porque não?

10
@avastreg: APENAS FAÇA ISSO UMA VEZ . E irá mostrar-lhe as perguntas!

26

depois de um pouco de dor, eu entendi.

a melhor maneira de conseguir isso é listar todas as tabelas

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

e, em seguida, para cada tabela, liste todas as colunas com atributos

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

em seguida, para cada coluna, teste se há uma sequência

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

e, em seguida, obtenha as informações sobre essa sequência

select * from <sequence_name>

13

informações da sequência: valor máximo

SELECT * FROM information_schema.sequences;

informação da sequência: último valor

SELECT * FROM <sequence_name>


11

O relacionamento entre sequências geradas automaticamente (como aquelas criadas para colunas SERIAL) e a tabela pai é modelado pelo atributo do proprietário da sequência.

Você pode modificar esse relacionamento usando a cláusula OWNED BY do comando ALTER SEQUENCE

por exemplo, ALTER SEQUENCE foo_id POSSUÍDO por foo_schema.foo_table

para configurá-lo para ser vinculado à tabela foo_table

ou ALTER SEQUENCE foo_id POSSUÍDO por NENHUM

para quebrar a conexão entre a sequência e qualquer tabela

As informações sobre esse relacionamento são armazenadas na tabela de catálogo pg_depend .

o relacionamento de junção é o link entre pg_depend.objid -> pg_class.oid WHERE relkind = 'S' - que vincula a sequência ao registro de junção e, em seguida, pg_depend.refobjid -> pg_class.oid WHERE relkind = 'r', que vincula o registro de associação à relação de propriedade (tabela)

Essa consulta retorna todas as sequências -> dependências da tabela em um banco de dados. A cláusula where o filtra para incluir apenas relacionamentos gerados automaticamente, o que o restringe a exibir apenas sequências criadas por colunas digitadas 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' ;

Explicação útil das dependências entre tabelas e seqüências. Mas sua consulta não encontrou todas as seqüências para mim. Parece que algumas seqüências existem sem nenhuma dependência.
— Evgeny Nozdrev

sim, esta consulta está demonstrando explicitamente apenas sequências definidas pelas definições de coluna serial do banco de dados. Isso é explicado na resposta.
— CMS

5

Sei que este post é bastante antigo, mas achei a solução do CMS muito útil, pois estava procurando uma maneira automatizada de vincular uma sequência à tabela AND coluna e queria compartilhar. O uso da tabela de catálogo pg_depend foi a chave. Expandi o que foi feito 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 versão adiciona coluna à lista de campos retornados. Com o nome da tabela e o nome da coluna em mãos, uma chamada para pg_set_serial_sequence facilita a garantia de que todas as seqüências no banco de dados estejam definidas corretamente. Por exemplo:

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 isso ajude alguém a redefinir sequências!


alguns anos depois, percebo a sua atualização, e pop por dar uma upvote :-)
— cms

3

Esta instrução lista a tabela e a coluna que estão associadas a cada sequência:

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'

mais veja aqui link para responder


2

Melhoria da resposta 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, não basta colocar seu código sem nenhuma explicação. Além disso, como você declarou que seu código é uma "Melhoria da resposta anterior", você também deve nos dizer POR QUE é uma melhoria. Ah, não desista e seja bem-vindo ao SO!
— Joel

Devo escrever uma página de texto sem sentido em vez de um código preciso (duas linhas)?
— Alexander Ryabov

2
Nunca disse isso. Eu gosto de código simples e preciso. Porém, ao afirmar que seu código é uma melhoria, uma ou duas linhas que explicam POR QUE é uma melhoria (melhor legibilidade, melhor desempenho etc.) não prejudicam. E você provavelmente receberá um +1 de mim também.
— Joel #

1

Parcialmente testado, mas parece quase 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 onde o crédito é devido ... é parcialmente modificado com a engenharia reversa do SQL registrado a partir de \ d em uma tabela conhecida que tinha uma sequência. Tenho certeza de que também poderia ser mais limpo, mas ei, desempenho não era uma preocupação.


1

Como um hack, mas tente o seguinte:

selecione 'selecionar' '' || relname || '' 'como sequência, last_value de' || relname || 'união' FROM pg_catalog.pg_class c WHERE c.relkind IN ('S', '');

Remova o último UNION e execute o resultado


1

Obtenha sequências para cada coluna de cada tabela através da análise da cláusula DEFAULT. Este método fornece informações sobre a quais sequências de colunas estão vinculadas e não usa dependências que podem não existir para algumas sequências. pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname)Função uniforme encontrada nem todas sequências para mim!

Solução:

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;

Observe que 1 sequência pode ser usada em várias tabelas, portanto, pode ser listada em várias linhas aqui.


0

Obrigado pela ajuda.

Aqui está a função pl / pgsql que atualiza cada sequência de um banco de dados.

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

Aqui está outro que tem o nome do esquema ao lado do nome da sequência

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

0

Esta função mostra o last_value de cada sequência.

Ele gera uma tabela de 2 colunas que diz o nome da sequência mais o seu último valor gerado.

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

Assumindo a exec()função declarada neste post https://stackoverflow.com/a/46721603/653539 , sequências juntamente com seus últimos valores podem ser buscadas usando uma única 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

Aqui está um exemplo de como usar psqlpara obter uma lista de todas as seqüências com 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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.