postgresql中returning子句必须紧跟insert/update/delete语句末尾,后接具体列名或*,仅postgresql原生支持,mysql等不兼容;它与dml原子绑定,返回实际被影响行的数据,字段名须严格匹配表定义。

RETURNING 在 PostgreSQL 中的正确写法
只有 PostgreSQL 原生支持 RETURNING 子句,MySQL、SQL Server、Oracle(需用 RETURNING INTO 配合 PL/SQL)都不直接等价。如果你在非 PostgreSQL 环境下看到类似语法报错,大概率是误用了方言。
典型写法是紧跟在 INSERT / UPDATE / DELETE 语句末尾,后接字段列表或 *:
UPDATE users SET status = 'archived' WHERE id = 123 RETURNING id, email, updated_at;
注意:RETURNING 不是独立语句,不能单独执行;也不能放在事务块外再“取结果”——它和 DML 是原子绑定的,结果集随语句一起返回。
INSERT ... RETURNING 获取自增 ID 的实际用法
这是最常见需求:插入一行后立刻拿到数据库生成的主键,避免二次查询。但容易忽略两点:字段名必须和目标表列一致(包括大小写),且不能引用未插入的计算列(除非是表达式本身)。
-
INSERT INTO orders (product, amount) VALUES ('book', 29.99) RETURNING id;✅ 安全可靠 -
INSERT INTO orders (...) VALUES (...) RETURNING order_id;❌ 若表中主键列名为id,这里写order_id会报错column "order_id" does not exist -
RETURNING id, NOW()✅ 允许返回函数表达式
UPDATE ... RETURNING 为什么有时返回空结果
不是语法错,而是匹配不到行——RETURNING 只返回被实际修改的行。哪怕 WHERE 条件成立,如果新旧值完全相同(比如 SET name = name),PostgreSQL 默认不触发更新,也就没有行可返回。
解决办法取决于场景:
- 确认业务逻辑是否真需要“无变更也返回”:可用
UPDATE ... SET col = col || '' RETURNING ...强制触发(慎用,影响性能) - 检查 WHERE 是否写错:比如
WHERE id = 'abc'(字符串)对整型主键,可能静默不匹配 - 用
GET DIAGNOSTICS rowcount = ROW_COUNT;(在 plpgsql 函数内)判断是否真的改了数据
RETURNING 和应用程序如何对接
多数客户端驱动(如 psycopg2、pgx、Npgsql)把 RETURNING 结果当作普通查询结果集处理,但要注意:它不是 SELECT,不能用 fetchall() 以外的方式随意游标移动(某些驱动不支持倒序读)。
常见陷阱:
- Node.js pg 模块中,
client.query()的result.rows直接就是RETURNING的数组,别误以为要额外await client.query('SELECT ...') - Java JDBC 需显式设置
Statement.RETURN_GENERATED_KEYS才能获取INSERT ... RETURNING,且只认RETURNING *或明确列出主键列 - Go pgx 默认支持,但若用
Exec而非Query,会丢弃结果 —— 必须用Query或QueryRow
最易被忽略的是错误处理边界:当 UPDATE ... RETURNING 匹配 0 行时,有些驱动返回空数组,有些抛异常(如旧版 psycopg2 的 fetchone() 在无结果时返回 None,但没做空检查就解构会崩)。










