【问题标题】:List all sequences in a Postgres db 8.1 with SQL使用 SQL 列出 Postgres db 8.1 中的所有序列
【发布时间】:2010-12-02 08:54:04
【问题描述】:

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

由于我找不到一个可以自己解决问题的工具,我打算将所有 postgres 序列转换为 mysql 中具有自动增量值的自动增量 ID。

那么,我如何使用 SQL 列出 Postgres 数据库(8.1 版本)中的所有序列以及有关使用它的表、下一个值等的信息查询?

请注意,我无法在 8.4 版本中使用 information_schema.sequences 视图。

【问题讨论】:

  • 应该注意的是你的转换方式不对。自从甲骨文收购了 Sun 以来,他们一直在慢慢扼杀 MySQL,所以除非你鄙视你的客户(在这种情况下你应该干脆退出),否则你应该坚持使用 PostgreSQL,因为没有公司(不赞成垄断)可以出现,吞噬 PostgreSQL 和最终用他们自己的数据库替换它。
  • @John 我会说有十亿和另外一个理由坚持使用 postgres,还有十亿个永远不要接触 mysql,但是是的 - 你的观点仍然非常有效:)跨度>
  • @John 当时(2009 年)我们需要一个更简单的数据库来处理 - mysql 更好地与 php 耦合

标签: sql database postgresql migration sequences


【解决方案1】:

以下查询给出所有序列的名称。

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

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

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

SELECT last_value FROM test_id_seq;

【讨论】:

  • ${table}_id_seq 提示很有用
  • ${table}_${column}_seq 用于自动创建的序列
【解决方案2】:

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

SELECT * FROM information_schema.sequences;

由于我使用的是更高版本的 PostgreSQL (9.1),并且一直在寻找相同的答案,所以为了后代和未来的搜索者,我添加了这个答案。

【讨论】:

  • Protip:按“活动”对答案进行排序。随着问题变得越来越老,后代变得越来越重要..
  • 酷。看起来如果我选择“活动”排序方法,该站点会立即记住该设置(这里我在首选项中四处挖掘以找到一个将其设置为默认值的位置无济于事)。嗯,现在如果我们有一个“被提问者接受的答案不会自动胜过其他一切”-选项,将是子孙后代真正的伟大胜利。跨度>
  • 请注意这个表是在 PG 8.4 中引入的,我宁愿在官方文档之后说 PG 8.2:postgresql.org/docs/8.2/infoschema-sequences.html
  • 那个“所有信息”不包括当前值。
  • 真的,你仍然需要使用SELECT last_value FROM <sequence_name> 来获得它。这个答案显示了序列的架构,这是我需要过滤的内容以及pg_class 视图不可用的内容。
【解决方案3】:

使用-E 标志启动psql(“回显\d 和其他反斜杠命令生成的实际查询”),然后输入\ds 命令列出所有序列。您应该会看到如下内容:

# \ds
********* QUERY **********
SELECT n.nspname as "Schema",
  c.relname as "Name",
  CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as "Type",
  pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('S','')
      AND n.nspname <> 'pg_catalog'
      AND n.nspname <> 'information_schema'
      AND n.nspname !~ '^pg_toast'
  AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
**************************

                     List of relations
 Schema |              Name              |   Type   | Owner 
--------+--------------------------------+----------+-------
 public | assignments_id_seq             | sequence | root
 public | framework_users_id_seq         | sequence | root
 public | lending_items_id_seq           | sequence | root
 public | proxy_borrower_requests_id_seq | sequence | root
 public | roles_id_seq                   | sequence | root
 public | stack_requests_id_seq          | sequence | root
(6 rows)

要检查特定序列,您可以运行\d &lt;sequence name&gt;

# \d lending_items_id_seq
********* QUERY **********

(...about four queries...)

**************************

                    Sequence "public.lending_items_id_seq"
  Type  | Start | Minimum |       Maximum       | Increment | Cycles? | Cache 
--------+-------+---------+---------------------+-----------+---------+-------
 bigint |     1 |       1 | 9223372036854775807 |         1 | no      |     1
Owned by: public.lending_items.id

【讨论】:

  • 我不仅需要序列列表,还需要使用它的表、下一个值等。而且我必须在 SQL 中执行此操作
  • 然后,在每个序列上执行 \d (仍在 psql -E 中)
  • 再一次,这不在 SQL 中,并且不显示序列附加在哪个表中
  • @avastreg:你按照我告诉你的方式运行了吗?为什么不呢?
  • @avastreg:只需 一次。它会向您显示查询!
【解决方案4】:

一阵阵痛后,我明白了。

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

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>

【讨论】:

    【解决方案5】:

    序列信息:最大值

    SELECT * FROM information_schema.sequences;

    序列信息:最后一个值

    SELECT * FROM <sequence_name>

    【讨论】:

      【解决方案6】:

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

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

      例如 由 foo_schema.foo_table 拥有的 ALTER SEQUENCE foo_id

      将其设置为链接到表 foo_table

      或 ALTER SEQUENCE foo_id 由 NONE 拥有

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

      有关此关系的信息存储在pg_depend catalogue table 中。

      加入关系是 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' ;
      

      【讨论】:

      • 对表和序列之间的依赖关系的有用解释。但是您的查询为我找到了不是所有序列。似乎有些序列是存在的,没有任何依赖关系。
      • 是的,此查询明确地仅演示由数据库串行列定义定义的序列。答案中对此进行了解释。
      【解决方案7】:

      我知道这篇文章已经很老了,但我发现CMS 的解决方案非常有用,因为我正在寻找一种将序列链接到表和列的自动化方法,并想分享。使用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。我今天还在用这个。
      【解决方案8】:

      我知道问题是关于 postgresql 版本 8,但我在这里为想要获取版本 10 及更高版本的序列的人写了这个简单的方法

      你可以使用下面的查询

      select * from pg_sequences
      

      view-pg-sequences

      【讨论】:

        【解决方案9】:

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

        代码:

            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'
        

        更多请看这里link to answer

        【讨论】:

          【解决方案10】:

          获取所有序列:

          select * from pg_sequences;
          

          PSQL:

          \ds
          \ds+
          \ds *actor*
          

          \ds *actor*会得到所有序列名称中包含actor个字符的序列。

          【讨论】:

            【解决方案11】:

            经过部分测试,但看起来基本完整。

            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 记录的 SQL 逆向工程的。我敢肯定它也可以更清洁,但是,嘿,性能不是问题。

            【讨论】:

              【解决方案12】:

              上一个答案的改进:

              select string_agg('select sequence_name, last_value from ' || relname, chr(13) || 'union' || chr(13) order by relname) 
              from pg_class where relkind ='S'
              

              【讨论】:

              • 请不要随便放你的代码而不做任何解释。此外,由于您已经声明您的代码是“对先前答案的改进”,您还应该告诉我们为什么它是一个改进。哦,不要放弃,欢迎来到 SO!
              • 我应该写一页无意义的文本而不是精确的代码(几行)?
              • 从来没有说过。我喜欢简单、精确的代码。但是当说明你的代码是一种改进时,一两行解释为什么它是一种改进(更好的可读性,改进的性能等)不会有任何伤害。你可能也会得到我的 +1。
              【解决方案13】:

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

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

              【讨论】:

                【解决方案14】:

                通过解析DEFAULT子句获取每个表的每一列的序列。此方法提供有关链接到哪些列序列的信息,并且不使用某些序列可能不存在的dependencies。甚至 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个序列可以在多个表中使用,所以这里可以多行列出。

                【讨论】:

                  【解决方案15】:

                  这个函数显示每个序列的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();
                  

                  【讨论】:

                    【解决方案16】:
                    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;
                    

                    【讨论】:

                      【解决方案17】:

                      有点骇人听闻,但试试这个:

                      select 'select ''' || relname  || ''' as sequence, last_value from '  || relname || '  union'
                      FROM pg_catalog.pg_class c
                      WHERE c.relkind IN ('S','');
                      

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

                      【讨论】:

                        【解决方案18】:

                        感谢您的帮助。

                        这里是更新数据库每个序列的 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();
                        

                        【讨论】:

                          【解决方案19】:

                          假设 exec() 在这篇文章 https://stackoverflow.com/a/46721603/653539 中声明的函数,可以使用单个查询获取序列及其最后的值:

                          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
                          

                          【讨论】:

                            【解决方案20】:

                            这是一个示例,如何使用psql 获取所有序列及其last_value 的列表:

                            psql -U &lt;username&gt; -d &lt;database&gt; -t -c "SELECT 'SELECT ''' || c.relname || ''' as sequence_name, last_value FROM ' || c.relname || ';' FROM pg_class c WHERE (c.relkind = 'S')" | psql -U &lt;username&gt; -d &lt;database&gt; -t

                            【讨论】:

                              猜你喜欢
                              • 2013-12-04
                              • 1970-01-01
                              • 2021-06-21
                              • 1970-01-01
                              • 2018-02-07
                              • 2015-04-27
                              • 2011-05-03
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多