PostgerSQL使用问答04 - Returning

本文是《PostgreSQL技术问答》系列文章中的一篇。文章的编号只是一个标识,在系列中没有明确的逻辑顺序和意义。

本文的主要内容是讨论Postgres的retuning 子句。

什么是Returning子句

Retuning子句是PostreSQL提供的一个SQL语句和特性。它可以用于在DML语句中,返回修改后的数据行。这个特性在Web应用开发中可能会非常有用,它可以极大的简化代码和操作。

例如,对于一个拥有自增字段的表,插入一条记录,插入后想要获取这条记录包括自增ID的话,传统的开发模式,可能需要进行额外的操作,例如使用插入数据进行查询或者类似MySQL中,LAST_INSERT_ID()这种方法。都需要执行多次查询,显得比较繁琐。

这时,使用Returning子句,就可以在插入数据后就获得这个插入的数据包括自增ID的值,非常简单和方便。此外,如果批量插入,又希望获得这些插入的记录,好像也只有这种方式满足要求。

Returing不是独立的SQL语句,而是一个子句,以Insert语句为例,在其中Returning子句的标准形式是(来自PostgreSQL官方技术文档):

sql 复制代码
[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
    [ OVERRIDING { SYSTEM | USER } VALUE ]
    { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
    [ ON CONFLICT [ conflict_target ] conflict_action ]
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

就是说,RETURING可以支持返回 * (所有字段),或者输出表达式(字段或者计算字段),并可以使用别名。

补充一下,在新的MySQL8版本中,也实现和支持Returning子句。

举个栗子?

我们先以插入数据也是Returning最常用的场景作为示例,如使用如下的数据表和查询:

js 复制代码
// 创建表
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(50) NOT NULL UNIQUE,
  passwd  VARCHAR(100) NOT NULL,
  upd_at int[]
);

// 插入并返回记录
insert into users(username,passwd,upd_at) values ('tom','','{0,1}') returning *;
 id | username | passwd | upd_at 
----+----------+--------+--------
  8 | tom      |        | {0,1}
(1 row)

INSERT 0 1

// 插入并返回特定字段
insert into users(username,passwd,upd_at) values ('david','','{0,1}') returning id, username;

// 插入并返回特定字段的别名
insert into users(username,passwd,upd_at) values ('smith','','{0,1}') returning id, username, upd_at[1] as create_at;

这个示例中,我们先用通常的方式,创建了一个数据表。指定主键ID是一个序列(自增整数)。然后插入仪表记录,这时虽然没有指定ID的值,但使用Returning子句,就可以返回创建完成后当前记录的值,包括ID。

Returning可以返回当前记录的值,也可以指定所返回记录的字段,这也是推荐的方式,因为使用 * 来表示所有字段,可能会增加数据库处理的负担,并且增加不确定性,增加产生无法预计结果的机会。

在Returning子句中也可以使用 as 关键字,修改输出字段的名称。

Update和Delete也可以吗?

当然可以,returning子句支持Insert、Update和Delete这些修改数据的操作类型。

sql 复制代码
// 删除并返回删除记录
delete from users where username='joe' returning *;
 id | username | passwd | upd_at 
----+----------+--------+--------
  4 | joe      |        | {0,1}
(1 row)

DELETE 1

// 更新并返回更新的记录
update  users set upd_at[1] = 100 where username='john' returning *;
 id | username | passwd | upd_at 
----+----------+--------+--------
  2 | john     |        | {100}
(1 row)

UPDATE 1

有什么需要注意的问题吗?

关于Retunring,笔者觉得有以下一些要点和需要注意的问题:

  • RETURNING子句结合了数据修改操作和操作结果的查询两个操作,本质上是一个语法糖
  • RETURNING是数据操作语句的一部分,修改和查询是一个原子化操作,可以保证更新和返回数据的一致性
  • 通常用于简化操作和查询编程
  • RUTURING子句也可以用于服务端语言如PL/pgSQL
  • RETURING并不限制在修改的字段和数据,而是涉及修改的记录
  • 需要注意其返回值是修改涉及的记录值,而不是当前记录值,它们可能一致,也可能不一致(如Delete操作)
  • 从技术文档上来看,似乎Returning不支持Postgres新的Merge语句?
相关推荐
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题 第87题】【Mysql篇】第17题:分布式事务的实现原理?
java·数据库·分布式·mysql·面试
yyuuuzz5 小时前
独立站的技术基础与常见运维问题
大数据·运维·服务器·网络·数据库·aws
红尘散仙5 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记6 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆7 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
喵个咪7 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6167 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364577 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao8 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
键盘上的猫头鹰8 小时前
【MySQL 教程(八)】索引、事务、用户管理、导入导出与分页查询
数据库·python·mysql