使用SQL列出Postgres db 8.1中的所有序列


147

我正在将数据库从postgres转换为mysql。

由于我找不到能自行解决问题的工具,因此我将使用autoincrement值将所有postgres序列转换为mysql中的autoincrement id。

因此,如何在Postgres DB(8.1版)中列出所有序列,以及有关使用该表的信息,下一个值等信息(通过SQL查询)?

请注意,我无法使用information_schema.sequences8.4版本中的视图。


1
应当注意,您执行错误的转换方式。自从Oracle收购Sun以来,他们一直在慢慢淘汰MySQL,因此除非您鄙视客户端(在这种情况下您应该退出),否则您应该坚持使用PostgreSQL,因为没有公司(没有垄断的公司)可以出现,吞噬PostgreSQL和最终用自己的数据库替换它。
约翰

@John我想说有十亿个理由和其他理由要坚持使用postgres,还有十亿个理由永远不要接触mysql,但是是的-您的观点仍然非常有效:)
Ruslan

@John当时(2009年),我们需要一个更简单的数据库来处理-并且mysql更好地与php耦合
apelliciari

Answers:


250

以下查询提供所有序列的名称。

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

通常,序列称为${table}_id_seq。简单的正则表达式模式匹配将为您提供表名。

要获取序列的最后一个值,请使用以下查询:

SELECT last_value FROM test_id_seq;

5
${table}_id_seq提示是有用的
皮埃尔·德·LESPINAY

${table}_${column}_seq自动创建的序列的方法
Evgeny Nozdrev

80

请注意,从PostgreSQL 8.4开始,您可以通过以下方式获取有关数据库中使用的序列的所有信息:

SELECT * FROM information_schema.sequences;

由于我使用的是更高版本的PostgreSQL(9.1),并且正在搜索相同的答案,因此,我为后代和将来的搜索者添加了此答案。


1
提示:按“有效”排序答案。随着问题变得越来越老
后代

1
凉。看起来,如果我选择“主动”排序方法,则该站点会立即记住该设置(在这里我一直在偏好中寻找位置,以将其设置为默认无效)。嗯,现在,只要我们有一个“接受问询的答案不会自动胜过其他一切”选项,对后代来说将是一次真正的伟大胜利。
SeldomNeedy

请注意,请确保该表是在PG 8.4中引入的,我更愿意在官方文档之后使用PG 8.2:postgresql.org/docs/8.2/infoschema-sequences.html
Guillaume Husta,

该“所有信息”不包括当前值。
巴特

62

运行:psql -E,然后\ds


1
我不需要序列列表,我需要使用它的表,下一个值等。而且我必须在SQL中执行
apelliciari

然后,在每个序列上执行\ d <名称>(仍在psql -E中)

再次,这不在SQL中,并且不显示该序列附加在哪个表上
apelliciari

@avastreg:您是否按照我告诉您的方式运行它?那么为何不?

10
@avastreg:只做一次。它将向您显示查询!

26

有点痛苦后,我明白了。

实现此目的的最佳方法是列出所有表

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

然后,对于每个表,列出所有具有属性的列

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

然后,针对每一列,测试其是否具有序列

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

然后,获取有关此序列的信息

select * from <sequence_name>

13

序列信息:最大值

SELECT * FROM information_schema.sequences;

序列信息:最后一个值

SELECT * FROM <sequence_name>


11

自动生成的序列(例如为SERIAL列创建的序列)与父表之间的关系由序列所有者属性建模。

您可以使用ALTER SEQUENCE命令的OWNED BY子句修改此关系

例如ALTER SEQUENCE foo_id由foo_schema.foo_table拥有

将其设置为链接到表foo_table

或ALTER SEQUENCE foo_id由NONE拥有

断开序列和任何表之间的连接

有关此关系的信息存储在pg_depend目录表中

联接关系是pg_depend.objid-> pg_class.oid WHERE relkind ='S'之间的链接-将序列链接到联接记录,然后是pg_depend.refobjid-> pg_class.oid WHERE relkind ='r',该链接之间将记录加入拥有关系(表)

该查询返回数据库中的所有序列->表依赖性。where子句将其过滤为仅包括自动生成的关系,这将其限制为仅显示由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' ;

表和序列之间的依赖关系的有用说明。但是您的查询并未找到适合我的所有序列。似乎有些序列存在而没有任何依赖性。
Evgeny Nozdrev

是的,此查询明确仅显示了数据库序列列定义所定义的序列。答案中对此进行了解释。
cms

5

我知道这篇文章很老,但是我发现CMS的解决方案非常有用,因为我正在寻找一种将序列链接到表AND列的自动方法,并希望共享。使用pg_depend目录表是关键。我将所做的事情扩展到:

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

此版本将列添加到返回的字段列表中。有了表名和列名,对pg_set_serial_sequence的调用可以轻松确保正确设置数据库中的所有序列。例如:

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

希望这对重置序列有帮助!


几年后,我注意到您的更新,然后弹出进行投票:-)
cms

3

此语句列出与每个序列关联的表和列:

码:

    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'

更多请看这里链接答案


2

先前答案的改进:

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
请不要只是在没有任何解释的情况下放置您的代码。另外,由于您已经声明您的代码是“对先前答案的改进”,因此您还应该告诉我们为什么这是一种改进。哦,不要放弃,欢迎来到!
乔尔2014年

我应该写一个无意义的文本页面,而不是精确的代码(几行)吗?
亚历山大·里亚博夫

2
没说过 我喜欢简单,精确的代码。但是,当说明您的代码是一种改进时,用一两行解释为什么会改进(更好的可读性,改进的性能等)不会受到伤害。而且您可能也会从我这里得到+1。
乔尔2014年

1

经过部分测试,但看起来大部分都完整。

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;

应归功于应归功的信贷...它是从已知\ d序列表中的\ d记录的SQL进行的反向工程。我敢肯定它也可以更清洁,但是嘿,性能不是问题。


1

有点骇客,但请尝试以下操作:

选择'选择'''|| relname || '''作为序列,来自'||的last_value relname || 'union'FROM pg_catalog.pg_class c WHERE c.relkind IN('S','');

删除最后一个UNION并执行结果


1

通过解析DEFAULT子句按每个表的每个列获取序列。此方法提供有关链接到哪些列序列的信息,并且不使用某些序列可能不存在的依赖项。甚至pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname)函数对我来说也不是全部序列!

解:

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;

请注意,1个序列可以在多个表中使用,因此可以在此处在多行中列出。


0

谢谢你的帮助。

这是pl / pgsql函数,用于更新数据库的每个序列。

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

这是另一个在序列名称旁边具有模式名称的名称

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

0

此函数显示每个序列的last_value。

它输出一个2列的表格,上面写着序列名称及其最后生成的值。

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

这是一个示例如何使用psql获取所有序列及其列表的列表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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.