AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 3281
Accepted
Jonas
Jonas
Asked: 2011-06-14 00:20:20 +0800 CST2011-06-14 00:20:20 +0800 CST 2011-06-14 00:20:20 +0800 CST

如何在 PostgreSQL 中使用 currval() 来获取最后插入的 id?

  • 772

我有一张桌子:

CREATE TABLE names (id serial, name varchar(20))

我想要该表中的“最后插入的 id”,而不使用RETURNING id插入。似乎有一个功能CURRVAL(),但我不明白如何使用它。

我尝试过:

SELECT CURRVAL() AS id FROM names_id_seq
SELECT CURRVAL('names_id_seq')
SELECT CURRVAL('names_id_seq'::regclass)

但它们都不起作用。如何使用currval()获取最后插入的 id?

postgresql sequence
  • 10 10 个回答
  • 286760 Views

10 个回答

  • Voted
  1. Slak
    2014-10-03T02:51:38+08:002014-10-03T02:51:38+08:00

    这直接来自 堆栈溢出

    正如@a_horse_with_no_name 和@Jack Douglas 所指出的,currval 仅适用于当前会话。因此,如果您对结果可能会受到另一个会话的未提交事务的影响这一事实感到满意,并且您仍然想要跨会话工作的东西,您可以使用它:

    SELECT last_value FROM your_sequence_name;
    

    使用指向 SO 的链接了解更多信息。

    但是,从Postgres 文档中,明确指出

    如果在当前会话中尚未调用 nextval,则调用 lastval 是错误的。

    所以我想严格来说,为了正确使用 currval 或 last_value 跨会话的序列,你需要做这样的事情吗?

    SELECT setval('serial_id_seq',nextval('serial_id_seq')-1);
    

    当然,假设您在当前会话中没有插入或任何其他使用串行字段的方式。

    • 77
  2. Best Answer
    a_horse_with_no_name
    2011-06-14T03:08:21+08:002011-06-14T03:08:21+08:00

    如果你创建一个列,serialPostgreSQL 会自动为它创建一个序列。

    序列的名称是自动生成的,并且始终是 tablename_columnname_seq,在您的情况下,序列将是 names names_id_seq。

    插入表后,您可以currval()使用该序列名称调用:

    postgres=> CREATE TABLE names in schema_name (id serial, name varchar(20));
    CREATE TABLE
    postgres=> insert into names (name) values ('Arthur Dent');
    INSERT 0 1
    postgres=> select currval('names_id_seq');
     currval
    ---------
           1
    (1 row)
    postgres=>
    

    除了硬编码序列名称,您还可以使用pg_get_serial_sequence():

    select currval(pg_get_serial_sequence('names', 'id'));
    

    这样你就不需要依赖 Postgres 使用的命名策略。

    或者,如果您根本不想使用序列名称,请使用lastval()

    • 74
  3. Jack Douglas
    2011-06-14T00:37:08+08:002011-06-14T00:37:08+08:00

    您需要nextval在此会话之前调用此序列currval:

    create sequence serial;
    select nextval('serial');
     nextval
    ---------
           1
    (1 row)
    
    select currval('serial');
     currval
    ---------
           1
    (1 row)
    

    因此,除非在同一会话中完成,否则您无法从序列中找到“最后插入的 id” insert(事务可能会回滚,但序列不会)

    正如 a_horse 的回答中所指出的,create table使用类型的列serial将自动创建一个序列并使用它来生成该列的默认值,因此insert通常会nextval隐式访问:

    create table my_table(id serial);
    NOTICE:  CREATE TABLE will create implicit sequence "my_table_id_seq" for 
             serial column "my_table.id"
    
    \d my_table
                              Table "stack.my_table"
     Column |  Type   |                       Modifiers
    --------+---------+-------------------------------------------------------
     id     | integer | not null default nextval('my_table_id_seq'::regclass)
    
    insert into my_table default values;
    select currval('my_table_id_seq');
     currval
    ---------
           1
    (1 row)
    
    • 16
  4. chander
    2017-08-05T06:35:33+08:002017-08-05T06:35:33+08:00

    因此,这些不同的方法存在一些问题:

    Currval 仅获取当前会话中生成的最后一个值 - 如果您没有任何其他生成值,这很好,但在您可能调用触发器和/或在当前事务中多次推进序列的情况下,它是不会返回正确的值。对于 99% 的人来说,这不是问题 - 但这是一个应该考虑的问题。

    获得插入操作后分配的唯一标识符的最佳方法是使用 RETURNING 子句。下面的示例假定与序列相关的列称为“id”:

    insert into table A (cola,colb,colc) values ('val1','val2','val3') returning id;
    

    请注意,RETURNING 子句的用处远不止获取序列,因为它还将:

    • 用于“最终插入”的返回值(例如,在 BEFORE 触发器可能更改了插入的数据之后。)
    • 返回被删除的值:

      从表 A 中删除,其中 id > 100 返回 *

    • 在 UPDATE 之后返回修改后的行:

      更新表 A set X='y' where blah='blech' 返回 *

    • 使用删除的结果进行更新:

      WITH A as (delete * from table A as returned id) update B set deleted=true where id in (select id from A);

    • 5
  5. scifisamurai
    2019-09-26T14:18:02+08:002019-09-26T14:18:02+08:00

    在 PostgreSQL 11.2 中,您可以将序列视为表:

    例如,如果您有一个名为的序列:'names_id_seq'

    select * from names_id_seq;
     last_value | log_cnt | is_called
    ------------+---------+-----------
              4 |      32 | t
    (1 row)
    

    这应该给你最后插入的 id(在本例中为 4),这意味着当前值(或下一个应该用于 id 的值)应该是 5。

    • 2
  6. Jalal
    2016-01-13T08:24:27+08:002016-01-13T08:24:27+08:00

    尽管使用了 SQLALchemy,但我不得不执行查询,因为我没有成功使用 currval。

    nextId = db.session.execute("select last_value from <table>_seq").fetchone()[0] + 1
    

    这是一个 python flask + postgresql 项目。

    • 1
  7. Christophe
    2018-09-27T10:10:10+08:002018-09-27T10:10:10+08:00

    如果您想在不调用nextval()且无需修改序列的情况下获取序列的值,我将一个 PL/pgSQL 函数放在一起来处理它:查找所有数据库序列的值

    • 1
  8. AMML
    2018-12-13T06:55:03+08:002018-12-13T06:55:03+08:00

    您需要GRANT在架构上使用,如下所示:

    GRANT USAGE ON SCHEMA schema_name to user;
    

    和

    GRANT ALL PRIVILEGES ON schema_name.sequence_name TO user;
    
    • 1
  9. José Manuel Ruiz Baena
    2020-06-20T10:09:34+08:002020-06-20T10:09:34+08:00
    select  *, 'select '''||secuencia||''' as secuencia, nextval('''||secuencia||''') as currentval, (select max('||campo||') from '||tabla||') as maxtabla UNION ALL ' as sentencia from (
    select 
    relname as secuencia
    , substr(relname,0, strpos(relname, SPLIT_PART(relname, '_', nseparadores))-1 ) as tabla -- tabla sobre el que hace referencia la secuencia
    --, strpos(relname, SPLIT_PART(relname, '_', nseparadores)) as posicion_campo --posición donde comienza el nombre del campo
    ,SPLIT_PART(relname, '_', nseparadores) as campo -- campo sobre el que hace referencia la secuencia
    from (
    select nspname, relname, length(relname) - length(replace(relname, '_', '')) as nseparadores  from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = 'S' order by nspname
    ) sentencia01
    ) sentencia02
    
    • 0
  10. Robin
    2015-10-29T08:07:17+08:002015-10-29T08:07:17+08:00

    不同版本的 PostgreSQL 可能有不同的函数来获取当前或下一个序列 id。

    首先,您必须知道 Postgres 的版本。使用选择版本();获取版本。

    在 PostgreSQL 8.2.15 中,您可以使用select last_value from schemaName.sequence_name.

    如果上述语句不起作用,您可以使用select currval('schemaName.sequence_name');

    • -2

相关问题

  • 我可以在使用数据库后激活 PITR 吗?

  • 运行时间偏移延迟复制的最佳实践

  • 存储过程可以防止 SQL 注入吗?

  • PostgreSQL 中 UniProt 的生物序列

  • PostgreSQL 9.0 Replication 和 Slony-I 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    您如何显示在 Oracle 数据库上执行的 SQL?

    • 2 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    我可以查看在 SQL Server 数据库上运行的历史查询吗?

    • 6 个回答
  • Marko Smith

    如何在 PostgreSQL 中使用 currval() 来获取最后插入的 id?

    • 10 个回答
  • Marko Smith

    如何在 Mac OS X 上运行 psql?

    • 11 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Marko Smith

    将数组参数传递给存储过程

    • 12 个回答
  • Martin Hope
    Manuel Leduc PostgreSQL 多列唯一约束和 NULL 值 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler 什么时候应该将主键声明为非聚集的? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - 哪个更好作为主键? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick 如何优化大型数据库的 mysqldump? 2011-01-04 13:13:48 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve