PostgreSQL手动修改序列

342

我正在尝试将一个序列设置为特定的值。

SELECT setval('payments_id_seq'), 21, true;

以下代码会报错:

ERROR: function setval(unknown) does not exist

使用 ALTER SEQUENCE 也似乎不起作用?

ALTER SEQUENCE payments_id_seq LASTVALUE 22;

如何完成这个操作?

参考:https://www.postgresql.org/docs/current/functions-sequence.html


5
setval()似乎至少有两个参数。 - user554546
8个回答

536
括号放错位置了:
SELECT setval('payments_id_seq', 21, true);  -- next value will be 22
否则您只用一个参数调用setval,而它需要两个或三个参数。
这与SELECT setval('payments_id_seq', 21)相同。

12
最后一个参数"true"是什么意思? - inafalcao
60
true 表示下一个值将是提供的数字加1,这里是22。false 表示下一个值将是提供的数字本身,即21。默认情况下,setval 的行为就像选择了 true 一样。更多详情请参考:https://www.postgresql.org/docs/9.6/static/functions-sequence.html - Tom Mertz
10
select setval 语法相对于 alter sequence 的一个优点是,你可以在其中使用嵌套查询,例如使用 select max(id) from payments - mariotomo
1
@mariotomo 这是一个非常好的观点,也是确保您不会意外地将序列号设置为低于当前最大值而引入潜在错误的最简单方法之一。 - John Neuhaus
3
使用这种函数的另一个优点是可以运行像 select setval('new_id_seq', nextval('old_id_seq'), false); 这样的查询,有助于迁移。 - Shiplu Mokaddim
如果需要从最大ID的值继续序列,您应该使用SELECT setval('payment_id_seq', (select coalesce(max(id), 0) from payment), true); - undefined

288
这个语法在任何版本的PostgreSQL中都是无效的。

ALTER SEQUENCE payments_id_seq LASTVALUE 22

这个可以行。
ALTER SEQUENCE payments_id_seq RESTART WITH 22;

而且等同于:

SELECT setval('payments_id_seq', 22, FALSE);

ALTER SEQUENCE序列函数的当前手册中有更多内容。

请注意,setval()函数期望的参数要么是(regclass, bigint)或者(regclass, bigint, boolean)。在上面的例子中,我提供了未指定类型的字面量。这也是可以的。但是如果你向函数传递了带有类型的变量,你可能需要使用显式的类型转换来满足函数类型解析的要求。例如:

SELECT setval(my_text_variable::regclass, my_other_variable::bigint, FALSE);

重新启动一个序列或IDENTITY列,使其从当前最大列值开始(甚至不知道序列名称):
SELECT setval(pg_get_serial_sequence('payments', 'id')
            , COALESCE(max(id) + 1, 1)
            , false)
FROM   payments;

请参见:
对于重复操作,您可能会感兴趣的是:
ALTER SEQUENCE payments_id_seq START WITH 22; -- set default
ALTER SEQUENCE payments_id_seq RESTART;       -- without value

START [WITH] 存储一个默认的 RESTART 数字,用于后续的 RESTART 调用而无需提供值。最后一部分需要使用 Postgres 8.4 或更高版本。


8
ALTER SEQUENCE [sequence] RESTART WITH (SELECT MAX(col) from table); 这段代码不起作用,而 SELECT setval('sequence', (SELECT (MAX(col) from table), TRUE); 能够正常工作。我遇到了语法错误。(Postgres 9.4) - NuclearPeon
2
DDL命令(“实用程序命令”)中不允许使用子查询。请参见:https://stackoverflow.com/a/36025963/939860 - Erwin Brandstetter
1
@MitalPritmani:你可能需要类型转换。考虑在上面添加指令。 - Erwin Brandstetter
2
@NuclearPeon 我想你的意思是 SELECT setval('sequence', (SELECT MAX(col) from table), TRUE); 否则你的括号不匹配。 - dland
5
@dland:顺便提一下,更简洁更快的等价语句是:SELECT setval('seq', max(col)) FROM tbl; 参考链接:https://dev59.com/eXVC5IYBdhLWcg3wlyQo#23390399 - Erwin Brandstetter
显示剩余3条评论

72

使用 select setval('payments_id_seq', 21, true);

setval 包含 3 个参数:

  • 第一个参数是 sequence_name
  • 第二个参数是下一个 nextval
  • 第三个参数是可选的。

setval 的第三个参数中使用 true 或 false 如下所示:

SELECT setval('payments_id_seq', 21);           // Next nextval will return 22
SELECT setval('payments_id_seq', 21, true);     // Same as above 
SELECT setval('payments_id_seq', 21, false);    // Next nextval will return 21

为避免硬编码序列名称、下一个序列值并正确处理空列表,您可以使用以下方法:

SELECT setval(pg_get_serial_sequence('table_name', 'id'), coalesce(max(id), 0)+1 , false) FROM table_name;

其中table_name是表名,id是该表的主键


3
谢谢!最后一句话正是我在寻找的。它允许我保留序列值以便之后批量插入。 - Tim
1
这是最正确的答案,最后的SQL片段是最通用和有效的。 - Mick Byrne
第一条评论:“下一个nextval将返回22”。只有当序列的增量值为1时才会这样。它将是21加上增量值。第三条评论:“下一个nextval将返回21”。这总是正确的。有时为了减少网络流量,应用程序会获取10个ID供使用,而无需连续询问10次。下一次,nextval返回的值将增加10而不是1。 在此处查看增量 https://www.postgresql.org/docs/current/sql-createsequence.html - Arpad Horvath -- Слава Україні

10

选择设置序列名的值为序列值


6
我不尝试通过 setval 更改序列的顺序。但是使用 ALTER,我发现了如何正确编写序列名称。以下对我有效:
  1. 使用 SELECT * FROM information_schema.sequences; 检查所需序列名称。

  2. ALTER SEQUENCE public."table_name_Id_seq" restart {number};

    在我的情况下,它是 ALTER SEQUENCE public."Services_Id_seq" restart 8;

此外,wiki.postgresql.org 上还有一个页面,描述了一种生成 SQL 脚本以一次性修复所有数据库表中序列的方法。以下是链接中的文本:

Save this to a file, say 'reset.sql'

SELECT 'SELECT SETVAL(' ||
       quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) ||
       ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1) ) FROM ' ||
       quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';'
FROM pg_class AS S,
     pg_depend AS D,
     pg_class AS T,
     pg_attribute AS C,
     pg_tables AS PGT
WHERE S.relkind = 'S'
    AND S.oid = D.objid
    AND D.refobjid = T.oid
    AND D.refobjid = C.attrelid
    AND D.refobjsubid = C.attnum
    AND T.relname = PGT.tablename
ORDER BY S.relname;

Run the file and save its output in a way that doesn't include the usual headers, then run that output. Example:

psql -Atq -f reset.sql -o temp
psql -f temp
rm temp

输出结果将会是一组SQL命令,其格式与以下命令完全相同:

SELECT SETVAL('public."SocialMentionEvents_Id_seq"', COALESCE(MAX("Id"), 1) ) FROM public."SocialMentionEvents";
SELECT SETVAL('public."Users_Id_seq"', COALESCE(MAX("Id"), 1) ) FROM public."Users";

2
这对我有用:

这对我有用:

SELECT pg_catalog.setval('public.hibernate_sequence', 3, true);

1

这个修改对我有效:

ALTER SEQUENCE payments_id_seq
    RESTART 17;

enter image description here


0

对于大多数人来说,setval命令应该可以工作,但是我的没有工作,所以我使用了pg_catalog.setval

这个对我起作用:

select pg_catalog.setval('<sequence_variable_name>', <sequence_number_you_want>, true);

setval函数单独对我来说没有起作用。
SELECT pg_catalog.setval('payments_id_seq', 21, true); -- next will be 22

查看文档以获取更多信息


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接