当前位置: 首页 > news >正文

PostgreSQL 中 CTE 的使用

PostgreSQL 中 CTE 的语法。CTE(Common Table Expression,通用表表达式)是一个非常强大且常用的功能,它极大地提高了复杂查询的可读性和可维护性。

核心概念

CTE 可以理解为一个临时的、命名的结果集,它只在一条 SQL 语句的执行范围内存在。你可以把它看作是在查询中定义的临时视图。


基本语法结构

WITH [RECURSIVE] cte_name [ (column_name [, ...]) ] AS (-- CTE 的定义(一个 SELECT 语句)SELECT ...
)
-- 主查询,使用上面定义的 CTE
SELECT *
FROM cte_name;

关键组成部分:

  1. WITH 关键字: 标志着 CTE 的开始。

  2. RECURSIVE 关键字(可选): 如果 CTE 是递归的,则必须加上此关键字。

  3. cte_name: 你为这个临时结果集起的名字。

  4. (column_name [, ...])(可选): 显式指定 CTE 结果集的列名。如果省略,则列名来自 SELECT 语句中的列。

  5. AS ( ... ): 括号内是定义 CTE 的 SELECT 语句。

  6. 主查询: 在定义完所有 CTE 后,编写主 SELECT(或 INSERTUPDATEDELETE)语句来使用这些 CTE。


示例 1:简单的非递归 CTE(提高可读性)

场景: 我们想找出销售额高于平均销售额的产品。

不使用 CTE 的写法(较难读):

SELECT product_id, SUM(amount) as total_sales
FROM sales
GROUP BY product_id
HAVING SUM(amount) > (SELECT AVG(sales_sum) FROM (SELECT SUM(amount) as sales_sum FROM sales GROUP BY product_id) AS avg_sales);

使用 CTE 的写法(清晰易懂):

WITH product_sales AS (-- CTE 1: 计算每个产品的总销售额SELECT product_id, SUM(amount) AS total_salesFROM salesGROUP BY product_id
),
average_sales AS (-- CTE 2: 计算所有产品的平均销售额SELECT AVG(total_sales) AS avg_salesFROM product_sales -- 可以引用之前定义的 CTE!
)
-- 主查询
SELECT ps.product_id, ps.total_sales
FROM product_sales ps, average_sales av
WHERE ps.total_sales > av.avg_sales;

优势: 将复杂的子查询拆解成有意义的命名模块(product_salesaverage_sales),逻辑一目了然。


示例 2:在 DML 语句中使用 CTE

CTE 不仅可用于 SELECT,还可用于 INSERTUPDATEDELETE

INSERT with CTE:

WITH top_products AS (SELECT product_idFROM salesGROUP BY product_idORDER BY SUM(amount) DESCLIMIT 10
)
INSERT INTO popular_products (product_id)
SELECT product_id
FROM top_products;

UPDATE with CTE:

WITH old_records AS (SELECT idFROM eventsWHERE created_at < NOW() - INTERVAL '1 year'
)
UPDATE events
SET archived = true
WHERE id IN (SELECT id FROM old_records);

DELETE with CTE:

WITH duplicates AS (SELECT MIN(ctid) as min_ctid, -- ctid 是 PostgreSQL 的系统列,代表行的物理位置user_id, emailFROM usersGROUP BY user_id, emailHAVING COUNT(*) > 1
)
DELETE FROM users
WHERE (user_id, email) IN (SELECT user_id, email FROM duplicates)AND ctid NOT IN (SELECT min_ctid FROM duplicates);

示例 3:递归 CTE(处理层次结构或序列)

递归 CTE 是 CTE 最强大的功能之一,用于处理树形结构、图数据或生成序列。其语法有固定结构。

基本递归结构:

WITH RECURSIVE cte_name AS (-- 1. 非递归项(锚点成员)SELECT ... FROM ... WHERE ...UNION [ALL]-- 2. 递归项(递归成员)SELECT ... FROM cte_name, ... WHERE ...
)
SELECT * FROM cte_name;

经典示例:生成 1 到 10 的数字序列

WITH RECURSIVE numbers AS (-- 锚点成员:起始值SELECT 1 AS nUNION ALL-- 递归成员:基于前一个值 +1,直到条件不满足SELECT n + 1FROM numbersWHERE n < 10 -- 终止条件
)
SELECT n FROM numbers;

结果: 1, 2, 3, ..., 10

经典示例:遍历员工-经理层级关系
假设表 employees(emp_id, emp_name, manager_id)

WITH RECURSIVE employee_hierarchy AS (-- 锚点成员:找出所有最高层级的员工(没有经理)SELECT emp_id, emp_name, manager_id,1 AS level,ARRAY[emp_id] AS path -- 用于记录从根到当前节点的路径FROM employeesWHERE manager_id IS NULLUNION ALL-- 递归成员:连接下属员工SELECT e.emp_id, e.emp_name, e.manager_id,eh.level + 1,eh.path || e.emp_id -- 将当前员工ID追加到路径中FROM employees eINNER JOIN employee_hierarchy eh ON e.manager_id = eh.emp_id
)
SELECT emp_id, emp_name, level,path
FROM employee_hierarchy
ORDER BY path;

这个查询会输出整个公司的汇报层级结构。


重要特性和注意事项

  1. 多个 CTE: 一个 WITH 子句可以定义多个 CTE,用逗号分隔。

    WITH
    cte1 AS (...),
    cte2 AS (...),
    cte3 AS (...)
    SELECT ... FROM cte1, cte2, cte3 ...
  2. 作用域: CTE 只在紧随其后的主查询中有效。你不能在同一个 WITH 子句中先定义的 CTE 中引用后定义的 CTE。

  3. 性能: CTE 在 PostgreSQL 中通常被优化为代码内联。但对于递归 CTE 或与外部查询有复杂交互的情况,它可能会产生自己的执行计划。有时为了强制实现物化(将结果临时存储),可以使用 MATERIALIZED 关键字(PostgreSQL 12+):

    WITH cte_name AS MATERIALIZED ( ... )
  4. 递归 CTE 的终止: 必须确保递归部分最终能返回空结果,否则查询将进入无限循环。

总结

特性描述
目的创建临时命名结果集,简化复杂查询,实现递归查询。
基本语法WITH cte_name AS (SELECT ...) SELECT ... FROM cte_name;
递归语法WITH RECURSIVE cte_name AS (锚点 UNION ALL 递归) SELECT ...
适用语句SELECTINSERTUPDATEDELETE
主要优势提高可读性模块化复杂逻辑实现递归查询

CTE 是每个 PostgreSQL 使用者都必须掌握的核心特性,它能让你写出更清晰、更强大、更易于维护的 SQL 代码。

http://www.dtcms.com/a/470877.html

相关文章:

  • 网站开发语言怎么样wordpress底板版权
  • 【C语言加油站】C语言文件操作详解:从“流”的概念到文件的打开与关闭​
  • 涪陵网站建设公司国内可以上的网站
  • 国产CAD皇冠CAD(CrownCAD)三维建模教程:变压器
  • 网站博客程序logo智能设计一键生成器
  • 网站空间可以通过什么获取专业做鞋子的网站有哪些
  • 优秀企业网站设计欣赏电商网站建设意义
  • PwnKit提权漏洞复现:原理分析+环境搭建+渗透实践(CVE-2021-4034)
  • 李宏毅机器学习笔记19
  • 腾讯建设网站视频下载深圳坪山天气
  • 群晖wordpress主机兰州seo新站优化招商
  • Go语言实现HTML转PDF
  • 深入解析Java NIO:从BIO到Reactor模式的网络编程演进
  • 公司怎么做网站推广北京西站停车场收费标准
  • 企业网站系统手机版住房与城乡建设部建设环境工程技术中心网站
  • 非法期货做网站安康信息平台
  • MySQL安装包下载成功,如何跨版本备份迁移无忧?
  • ASM架构基础与核心概念
  • 每天五分钟深度学习:正则化技术解决过拟合(高方差)问题
  • 局域网建设个人网站美食网站设计论文
  • 使用 systemd 管理 MySQL 服务
  • 做网站客户最关心哪些问题下载百度电商平台app
  • 消防电器具工程量-图形识别快速计算
  • 印度股票市场数据接口,支持实时行情、IPO新股、公司信息、技术分析等多种功能
  • 顺德 网站开发 招聘工程平台网
  • 网站建设开发网站案例项目费用插画原画十大培训机构
  • 排查素材下载过慢或失败问题
  • 小网站托管费用大连网站建设 仟亿
  • 基于单片机的窗帘、灯光、空调智能家居控制系统设计
  • Docker存储体系深度解析