可以,PostgreSQL的RETURNING支持但仅限单表更新;多表需写main_table.;SQL Server用OUTPUT INSERTED.或DELETED.;MySQL 8.0.23+和SQLite 3.35.0+部分支持,旧版需SELECT+UPDATE两步。

PostgreSQL 的 RETURNING 能否返回所有字段?
可以,但必须显式列出字段名或用 *(仅限单表更新)。UPDATE ... RETURNING * 是最简写法,前提是没涉及 JOIN 或子查询——否则 PostgreSQL 会报错 ERROR: cannot return from a relation that is not the target of the INSERT/UPDATE/DELETE。
常见错误是以为 RETURNING * 在多表 UPDATE 中也生效,其实它只认主表。如果用了 FROM 子句关联其他表,就得手动写 RETURNING table_name.*,否则报错。
- 单表更新:直接用
RETURNING * - 带
FROM的更新(如关联查条件):必须写RETURNING main_table.* - 想返回计算字段或别名?得单独列出来,
*不包含它们
SQL Server 的 OUTPUT 怎么返回整行?
OUTPUT 不支持 *,必须明确指定列。最接近“所有字段”的写法是 OUTPUT INSERTED.* 或 OUTPUT DELETED.*,取决于你想要更新前还是更新后的值。
注意:如果表有计算列、稀疏列或托管类型(如 geography),INSERTED.* 仍会返回它们,但某些客户端驱动可能解析失败——建议在复杂表结构中优先列出关键业务字段。
- 更新后整行:用
OUTPUT INSERTED.* - 更新前整行:用
OUTPUT DELETED.* - 混合返回?可以,比如
OUTPUT INSERTED.id, DELETED.status, GETDATE() - 不能写
OUTPUT *,语法直接报错Incorrect syntax near '*'
MySQL 和 SQLite 没有原生 RETURNING,怎么绕过?
MySQL 8.0.23+ 支持 RETURNING,但仅限单表、且不支持 *;必须写全字段或用生成列别名。SQLite 3.35.0+ 也加了 RETURNING,行为类似 PostgreSQL,支持 *,但仅限无 JOIN 的 UPDATE。
老版本 MySQL/SQLite 用户常用两步法:先 SELECT 出待更新的行(带 WHERE 条件),再执行 UPDATE,靠应用层拼接结果。缺点是并发下可能被其他事务改掉——如果业务允许轻微不一致,这是最稳的 fallback 方案。
- MySQL 8.0.23+:支持
UPDATE ... RETURNING col1, col2,不支持RETURNING * - SQLite 3.35.0+:支持
RETURNING *,但要求语句里没JOIN、没子查询 - 低版本通用方案:用
SELECT ... FOR UPDATE(InnoDB)或BEGIN IMMEDIATE(SQLite)加事务锁住数据
跨数据库写法兼容性要注意什么?
没有银弹。RETURNING / OUTPUT 的语法、语义、甚至事务可见性都不同。比如 PostgreSQL 的 RETURNING 在语句提交前就返回结果,而 SQL Server 的 OUTPUT 在语句执行中就输出,可能被触发器干扰。
更隐蔽的问题是 NULL 处理:OUTPUT INSERTED.col 在该列为 NULL 时照常返回 NULL,但某些 ORM 会把未返回的列默认设为空字符串或 0——这容易掩盖字段是否真被更新。
- 别依赖
*跨库移植,字段增减会导致查询失败或静默截断 - 批量更新时,PostgreSQL 的
RETURNING返回全部匹配行,SQL Server 的OUTPUT也是,但 MySQL 的RETURNING受ROW_COUNT()影响,可能少于预期 - 如果用在存储过程里,SQL Server 的
OUTPUT可插入临时表,PostgreSQL 的RETURNING可直接作为 CTE 输入,能力不对等










