在PostgreSQL中,当表的主键使用自增方式生成时,执行INSERT操作后往往需要立刻拿到新插入行的自增ID,用于后续的业务逻辑处理,比如关联插入其他表的记录。使用RETURNING子句可以直接在插入语句执行完成后返回自增ID,不需要额外的查询操作。
PostgreSQL自增ID的常见实现方式
PostgreSQL中实现自增ID主要有两种方式,不同的实现方式在使用RETURNING子句时语法略有差异:
- SERIAL类型:早期PostgreSQL版本常用的自增实现,本质是创建一个序列,将字段默认值设为序列的下一个值。
- IDENTITY列:PostgreSQL 10及以上版本推荐的官方自增实现,符合SQL标准,分为GENERATED ALWAYS和GENERATED BY DEFAULT两种模式。
RETURNING子句基本语法
RETURNING子句可以跟在INSERT、UPDATE、DELETE语句之后,用于返回这些操作影响的行的指定字段值。对于INSERT返回自增ID的场景,基本语法如下:
INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...) RETURNING 自增ID字段名;
如果需要返回多个字段,可以在RETURNING后面用逗号分隔多个字段名,也可以直接使用RETURNING *返回整行数据。
不同自增ID场景的使用示例
1. SERIAL类型自增ID的返回
首先创建一张使用SERIAL自增ID的用户表:
-- 创建用户表,id为SERIAL自增主键
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
age INT
);
执行插入语句并返回自增ID:
-- 插入用户数据并返回自增id
INSERT INTO users (username, age)
VALUES ('张三', 25)
RETURNING id;
执行上述语句后,会直接返回新插入行的id值,比如返回结果为1。
2. IDENTITY列自增ID的返回
创建使用IDENTITY自增ID的订单表:
-- 创建订单表,id为IDENTITY自增主键
CREATE TABLE orders (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_no VARCHAR(32) NOT NULL,
user_id INT
);
插入订单数据并返回自增ID:
-- 插入订单数据并返回自增id
INSERT INTO orders (order_no, user_id)
VALUES ('ORD20240501001', 1)
RETURNING id;
同样会直接返回新生成的订单ID值。
多行插入时返回自增ID
如果需要一次插入多行数据,RETURNING子句会返回所有插入行的自增ID,每行对应一个结果:
-- 一次插入多行用户数据,返回所有自增id
INSERT INTO users (username, age)
VALUES ('李四', 22), ('王五', 28), ('赵六', 30)
RETURNING id;
执行后会返回三个ID值,分别对应三个新插入的用户记录。
在编程语言中使用返回的自增ID
在实际开发中,我们通常会通过编程语言的数据库驱动执行上述SQL,获取返回的自增ID。以下是Python使用psycopg2驱动的示例:
import psycopg2
# 连接PostgreSQL数据库
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 users (username, age) VALUES (%s, %s) RETURNING id",
("张三", 25)
)
# 获取返回的ID
new_id = cur.fetchone()[0]
print(f"新插入的用户ID为:{new_id}")
conn.commit()
cur.close()
conn.close()
注意事项
- RETURNING子句返回的是实际插入行的字段值,即使自增ID是通过触发器或者其他方式生成的,也能正确返回,不受生成方式影响。
- 如果INSERT语句没有插入任何行(比如违反约束导致插入失败),RETURNING子句不会返回任何结果。
- 在并发场景下,RETURNING子句返回的是当前事务插入行的ID,不会受到其他事务插入操作的影响,比先插入再查询的方式更安全。
相比先执行INSERT再执行SELECT currval('序列名')的方式,RETURNING子句不需要知道自增字段对应的序列名称,使用更简便,也避免了序列名称变更带来的问题。
PostgreSQLRETURNING子句自增IDINSERT语句修改时间:2026-07-01 20:00:36