在PostgreSQL的实际开发中,插入数据后获取自增主键ID是非常常见的需求,比如新增用户后需要获取用户ID去关联用户角色表,或者将新增记录的主键返回给前端做后续操作。下面介绍几种常用的实现方式。

一、使用RETURNING子句返回ID
这是PostgreSQL中最推荐、最常用的方式,INSERT语句支持搭配RETURNING子句,在插入数据的同时返回指定的字段值,对于自增主键的场景,直接返回主键字段即可。
首先我们创建一个测试表,主键使用SERIAL类型实现自增:
-- 创建测试表,id为自增主键
CREATE TABLE test_user (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
age INT
);插入单条数据并返回ID的SQL如下:
-- 插入数据并返回自增主键id
INSERT INTO test_user (username, age)
VALUES ('张三', 25)
RETURNING id;执行上述语句后,会直接返回刚插入记录的id值。如果需要返回多个字段,也可以在RETURNING后面跟上多个字段名,用逗号分隔即可。
如果是在应用程序中调用,比如使用Python的psycopg2库,可以这样获取返回的ID:
import psycopg2
# 连接数据库
conn = psycopg2.connect(
dbname="test_db",
user="postgres",
password="123456",
host="127.0.0.1",
port="5432"
)
cur = conn.cursor()
# 执行插入并返回ID
cur.execute("INSERT INTO test_user (username, age) VALUES (%s, %s) RETURNING id;", ("李四", 30))
insert_id = cur.fetchone()[0] # 获取返回的id
conn.commit()
print(f"插入成功,主键ID为:{insert_id}")
cur.close()
conn.close()二、查询序列当前值返回ID
如果表的主键是自增类型,PostgreSQL会自动为SERIAL类型的字段创建一个关联的序列,序列名通常是表名_字段名_seq的格式,比如上面的test_user表的id字段关联的序列是test_user_id_seq。
我们可以先插入数据,然后查询序列的当前值来获取刚插入的ID,但是这种方式需要注意并发问题:如果多个会话同时插入数据,查询到的序列值可能不是当前会话插入的那条记录的ID。
插入数据后查询序列当前值的SQL如下:
-- 插入数据
INSERT INTO test_user (username, age) VALUES ('王五', 28);
-- 查询序列当前值,注意并发场景下可能不准确
SELECT currval('test_user_id_seq');如果要在插入时同时获取序列下一个值再插入,也可以这样写,不过这种方式相当于自己管理ID,不如RETURNING子句方便:
-- 先获取下一个序列值
SELECT nextval('test_user_id_seq') INTO @next_id;
-- 插入数据时使用获取的ID
INSERT INTO test_user (id, username, age) VALUES (@next_id, '赵六', 32);
-- 此时@next_id就是插入记录的ID三、使用PL/pgSQL函数封装返回ID
如果有复杂的插入逻辑,或者需要在多个地方复用插入返回ID的逻辑,可以封装成PL/pgSQL函数,函数内部执行插入操作后返回ID。
创建函数的示例如下:
-- 创建插入用户并返回ID的函数
CREATE OR REPLACE FUNCTION insert_user_return_id(uname VARCHAR, uage INT)
RETURNS INT AS $$
DECLARE
new_id INT;
BEGIN
INSERT INTO test_user (username, age)
VALUES (uname, uage)
RETURNING id INTO new_id;
RETURN new_id;
END;
$$ LANGUAGE plpgsql;调用函数获取插入后的ID:
-- 调用函数插入数据并获取ID
SELECT insert_user_return_id('孙七', 35);四、几种方式的对比
下面通过表格对比几种方式的适用场景和优缺点:
| 实现方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| RETURNING子句 | 单条或批量插入,需要立即获取插入后ID | 语法简单,原生支持,并发安全,性能高 | 仅适用于PostgreSQL,其他数据库语法不同 |
| 查询序列当前值 | 简单场景,并发量低的业务 | 逻辑直观,容易理解 | 高并发场景下可能获取到错误的ID,需要先知道序列名称 |
| PL/pgSQL函数 | 复杂插入逻辑,需要复用插入逻辑 | 逻辑封装,复用性高,可处理复杂业务逻辑 | 需要创建函数,维护成本稍高 |
注意事项
- 优先使用RETURNING子句,这是PostgreSQL官方推荐的方式,不存在并发问题,也不需要额外查询。
- 如果使用查询序列的方式,一定要确保是在同一个会话中先插入再查询currval,否则可能获取到错误的值,因为currval返回的是当前会话中该序列最后一次nextval的值。
- 批量插入时RETURNING子句也可以返回所有插入记录的ID,比如插入多条数据:
INSERT INTO test_user (username, age) VALUES ('a',1), ('b',2) RETURNING id;,会返回所有插入记录的ID列表。
注意:如果表的主键使用的是IDENTITY类型(PostgreSQL 10及以上支持),RETURNING子句同样适用,用法和SERIAL类型完全一致。
PostgreSQL插入返回ID自增主键RETURNING子句修改时间:2026-05-30 21:44:43