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.