最后插入ID的PostgreSQL函数

在PostgreSQL中,如何将最后一个id插入表中

在MS SQL中有作用域\标识()

请不要建议我使用这样的东西:

从表中选择最大值(id)

tl;dr:转到选项3:插入并返回)

回想一下,在postgresql中,表没有“id”概念,只有序列(通常但不一定用作串行伪类型的代理主键的默认值)

如果您对获取新插入行的id感兴趣,有几种方法:


选项1:CURRVAL(<序列名称>)

例如:

在persons(lastname,firstname)值中插入('Smith','John');
选择currval('persons_id_seq');

序列的名称必须是已知的,它确实是任意的;在本例中,我们假设表persons有一个id列,该列是用SERIAL伪类型创建的。为了避免依赖于此并让您感觉更干净,您可以改用pg\u get\u serial\u sequence

在persons(lastname,firstname)值中插入('Smith','John');
选择currval(pg_get_serial_sequence('persons','id'));

警告:currval()仅在同一会话中执行了INSERT(已执行nextval())后才起作用


选项2:LASTVAL()

这与前面的类似,只是不需要指定序列名称:它查找最近修改的序列(始终在会话内部,与上面的警告相同)


CURRVALLASTVAL都是完全并发安全的。PG中序列的行为设计为不同的会话不会干扰,因此没有竞争条件的风险(如果另一个会话在我的INSERT和我的SELECT之间插入另一行,我仍然得到正确的值)

然而他们确实有一个微妙的潜在问题。如果数据库有一些触发器(或规则),在插入到persons表时,会在其他表中进行一些额外的插入。。。然后,LASTVAL可能会给我们错误的值。如果在同一张persons表中进行额外的插入,则问题甚至可能发生在CURRVAL(这种情况不太常见,但风险仍然存在)


选项3:插入并返回

将返回id的值('Smith','John')插入到persons(lastname,firstname)中;

这是获得身份证最干净、最有效、最安全的方法。它没有以前的任何风险

缺点?几乎没有:您可能需要修改调用INSERT语句的方式(在最坏的情况下,您的API或DB层可能不希望INSERT返回值);它不是标准的SQL(谁在乎);它从Postgresql 8.2(2006年12月…)开始提供


结论:如果可以,选择选项3。在其他地方,选择1

注意:如果您想要全局地获取上次插入的id(不一定由您的会话获取),那么所有这些方法都是无用的。为此,您必须求助于从表中选择max(id)(当然,这不会从其他事务中读取未提交的插入)

相反地,您应该从不使用从表中选择max(id)而不是上面3个选项中的一个,以获取您的INSERT语句刚刚生成的id,因为(除了性能)这不是并发安全的:在插入选择之间,另一个会话可能插入了另一条记录

发表评论