PostgreSQL 序列的下一个值?

Posted

技术标签:

【中文标题】PostgreSQL 序列的下一个值?【英文标题】:PostgreSQL next value of the sequences? 【发布时间】:2012-11-03 19:43:08 【问题描述】:

我正在为我的 Codeigniter 网站使用 PostgreSQL。我正在使用杂货店杂货进行添加、编辑和删除操作。在进行编辑或添加时,我想根据内容的 id 动态重命名上传的文件。我可以使用杂货店的 callback_after_upload 函数来做到这一点。

在添加新内容时,我想要内容的下一个 id。我尝试使用nextval() 函数,但序列随之增加。不使用nextval()函数如何获取序列的最后一个值?

或者有什么简单的方法可以做到这一点?

【问题讨论】:

@saji89:实际上,这也已经过时并且不必要地低效了。您可以通过 one 往返服务器来执行此操作。我添加了一个答案。 @ErwinBrandstetter 仍然值得一提的是,在插入中使用的单独 nextval 调用的 mu 演示,因为与 INSERT ... RETURNING 不同,两者都将通过查询生成引擎和其他可能的痛苦事情工作不明白RETURNING 扩展:S @ErwinBrandstetter,感谢您提供的信息。 @CraigRinger:如果您的查询生成器不理解 RETURNING 子句(它已经存在多年了!),它也可能已经过时 - 或者只是看起来很糟糕的拐杖更换。尽管如此,提供备用解决方案 a_horse 还是很好的。没有争论。 【参考方案1】:

RETURNING

这可以通过单次往返到数据库:

INSERT INTO tbl(filename)
VALUES ('my_filename')
RETURNING tbl_id;

tbl_id 通常是serial or IDENTITY (Postgres 10 or later) column。 More in the manual.

显式获取值

如果filename 需要包含tbl_id(冗余),您仍然可以使用单个查询。

使用lastval()或更具体的currval()

INSERT INTO tbl (filename)
VALUES ('my_filename' || currval('tbl_tbl_id_seq')   -- or lastval()
RETURNING tbl_id;

见:

Reference value of serial column in another column during same INSERT

如果在此过程中可能会推进多个序列(即使通过触发器或其他副作用),确定的方法是使用currval('tbl_tbl_id_seq')

序列名称

在我的示例中,字符串文字 'tbl_tbl_id_seq' 应该是序列的实际 名称,并被强制转换为regclass,如果不是,则会引发异常该名称的序列可以在当前的search_path中找到。

tbl_tbl_id_seq 是表tbl 的自动生成的默认值,其序列列tbl_id。但没有任何保证。如果这样定义,列默认值可以从 any 序列中获取值。如果在创建表时使用默认名称,Postgres 会根据简单的算法选择下一个空闲名称。

如果您不知道serial 列的序列名称,请使用专用函数pg_get_serial_sequence()。可以即时完成:

INSERT INTO tbl (filename)
VALUES ('my_filename' || currval(pg_get_serial_sequence('tbl', 'tbl_id'))
RETURNING tbl_id;

db小提琴here旧sqlfiddle

【讨论】:

但是如果你生成的值应该被合并到被插入的值中,它并没有帮助。我对“以便我可以动态命名上传的文件”的理解是,i_nomad 想要将生成的 ID 放入正在插入到表中的值(文件名)之一。但这个问题非常不清楚,很难说。 @a_horse_with_no_name: tbl_id 无论如何都在序列列中表示。但是,如果您想将其包含在filename 中,您也可以这样做。在我的答案中添加了一些内容。【参考方案2】:

使用currval() 函数访问先前获得的序列值。

但这只会在nextval() 被调用之前 时返回一个值。

绝对没有办法“偷看”序列的下一个值而不实际获得它。

但是你的问题不清楚。如果在插入之前调用nextval(),则可以在插入中使用该值。或者更好的是,在您的插入语句中使用currval()

select nextval('my_sequence') ...

... do some stuff with the obtained value

insert into my_table(id, filename)
values (currval('my_sequence'), 'some_valid_filename');

【讨论】:

我正在使用杂货店杂货进行插入删除编辑操作。我正在使用“callback_after_upload”函数重命名文件。我没有为插入传递 id。 @i_nomad:这个杂货店的东西突然从哪里来的?你问了一个关于在 PostgreSQL 中使用序列的问题。 是的,它是关于在 PostgreSQL 中使用序列,我只是在解释我想用序列的“nextval”做什么。【参考方案3】:

我偶然发现了这个问题 b/c 我试图按表查找下一个序列值。这没有回答我的问题,但这就是它的完成方式,它可以帮助那些不是按名称而是按表查找序列值的人:

SELECT nextval(pg_get_serial_sequence('<your_table>', 'id')) AS new_id; 

希望对你有帮助:)

【讨论】:

【参考方案4】:

如果你不在会话中,你可以 nextval('you_sequence_name') 就可以了。

【讨论】:

【参考方案5】:

从字面上回答你的问题,这里是如何在不增加序列的情况下获取下一个值:

SELECT
 CASE WHEN is_called THEN
   last_value + 1
 ELSE
   last_value
 END
FROM sequence_name

显然,在实践中使用此代码并不是一个好主意。 不能保证下一行确实有这个 ID。 但是,出于调试目的,知道序列的值而不增加它可能会很有趣,这就是您可以做到的方法。

【讨论】:

【参考方案6】:

即使可以以某种方式做到这一点,这也是一个糟糕的主意,因为有可能获得一个序列,然后被另一个记录使用!

一个更好的主意是保存记录,然后检索序列。

【讨论】:

这不是真的。见postgresql.org/docs/8.1/static/functions-sequence.html【参考方案7】:

我试过了,效果很好

@Entity
public class Shipwreck 
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
  @Basic(optional = false)
  @SequenceGenerator(name = "seq", sequenceName = "shipwreck_seq", allocationSize = 1)
  Long id;

....

CREATE SEQUENCE public.shipwreck_seq
    INCREMENT 1
    START 110
    MINVALUE 1
    MAXVALUE 9223372036854775807
    CACHE 1;

【讨论】:

以上是关于PostgreSQL 序列的下一个值?的主要内容,如果未能解决你的问题,请参考以下文章

postgreSQL怎样创建一个序列号/自动递增的字段

PostgreSQL 分析函数窗口化以查找列中的下一个值

org.postgresql.util.PSQLException:没有为参数 1 指定值。- Postgres

合并 postgres 数据

Postgresql 序列性能

在 Ruby on Rails 3.2.14 / Ruby 2.0.0 / PostgreSQL 9.2.4 中使用 activerecord 从序列中检索 nextval