如何使用SQL WITH语句提升查询可读性?

落晨大大_8171

落晨大大_8171

2026-08-21

911人浏览

原创

with子句应单一职责、业务命名、避免缩写、小写下划线、逗号分隔、顺序引用、禁循环依赖、显式列名、group by合规、递归慎用——重在可读性与协作效率。

如何使用sql with语句提升查询可读性?

每个WITH子句只做一件事,命名必须带业务含义

WITH 当成变量声明来用,而不是换行工具。比如 active_users_30d 只过滤用户状态和时间范围,不 JOIN 订单;shipped_orders 只取 status = 'shipped' 的订单,不查用户字段。

命名别用 tmp1subq_a 这类代号,而要体现数据含义和时效性:daily_active_users_jul2024daus 更安全,尤其当多人协作或后期维护时。

  • 链式依赖可加前缀:如 user_baseuser_with_ltvhigh_value_cohort,一眼看出计算流向
  • 避免缩写歧义:rev 可能是 revenue、review 或 reversal;revenue_q2_2024 不会猜错
  • MySQL 8.0+ 和 PostgreSQL 对大小写敏感策略不同,统一用小写下划线命名最稳妥

多个CTE必须用逗号分隔,且引用顺序不能倒置

写多个 CTE 时,AS 后面必须紧跟括号,各 CTE 之间用英文逗号隔开——漏掉逗号在 MySQL 8.0+ 里直接报错 ERROR 1064 (42000)

CTE 执行顺序严格从上到下,后面定义的 CTE 不能被前面的引用。例如:

WITH
  order_counts AS (SELECT user_id, COUNT(*) AS cnt FROM orders GROUP BY user_id),
  high_freq_users AS (SELECT user_id FROM order_counts WHERE cnt > 5)  -- ✅ 正确:order_counts 已定义
SELECT * FROM high_freq_users;

但下面这样就会失败:

WITH
  high_freq_users AS (SELECT user_id FROM order_counts WHERE cnt > 5),  -- ❌ 报错:order_counts 尚未定义
  order_counts AS (SELECT user_id, COUNT(*) AS cnt FROM orders GROUP BY user_id)
SELECT * FROM high_freq_users;
  • 不能循环依赖:A 引用 B,B 又引用 A —— 数据库直接拒绝解析
  • PostgreSQL 允许在同一个 WITH 块里跨 CTE 引用(只要顺序对),MySQL 8.0+ 也支持,但 SQLite 旧版本不支持多 CTE
  • 别名冲突优先级:如果 CTE 名和物理表同名(比如都叫 users),MySQL 默认选物理表;PostgreSQL 则优先选 CTE,行为不一致需警惕

SELECT 必须显式列名,禁用 SELECT *

SELECT * 在 CTE 后主查询中极其危险:字段顺序可能因 CTE 内部 GROUP BY 或引擎优化而变化,尤其跨数据库迁移时容易错位。更糟的是,JOIN 多张表后不加前缀,立刻触发 Column 'id' is ambiguous 错误。

Image Creator
Image Creator

一款集成到Photoshop工作流中的AI图像生成插件,支持文字生图、图像生成与局部编辑等能力,辅助完成视觉设计。

下载

正确做法是:每个 CTE 的 AS 后换行写 SELECT,字段分行对齐,显式写出所有要用的列。

WITH
  shipped_orders AS (
    SELECT
      order_id,
      user_id,
      amount,
      created_at
    FROM orders
    WHERE status = 'shipped'
  )
SELECT
  u.name,
  so.amount,
  so.created_at
FROM users u
JOIN shipped_orders so ON u.id = so.user_id;
  • CTE 中若含 GROUP BY,所有非聚合字段必须出现在 GROUP BY 列表里,否则 MySQL 8.0+ 严格模式下报 ERROR 1055 (42000)
  • 字段别名要在 CTE 内部定义好,主查询直接用别名,别在主查询里再 AS 一次——易导致重复重命名或覆盖
  • CTE 定义时不声明列名(如 WITH x AS (SELECT a+b)),后续引用时字段名为 expr_1 这类系统生成名,极难调试

递归WITH RECURSIVE不是语法装饰,只用于真正不确定层级的场景

看到“上级-下级”结构就加 RECURSIVE,是中级 SQL 用户最常踩的坑。它不是高级勋章,而是专治树形遍历的手术刀。滥用会导致无限循环、栈溢出,或返回意料之外的中间结果。

必须同时满足三项才考虑递归 CTE:

  • 数据本身是自关联结构(如 employees.manager_id → employees.id
  • 层级深度不可预知(不能用 3 层 JOIN 硬写死)
  • 需要逐层展开路径(比如查某员工的所有下属,含间接下属)

锚点(anchor)和递归部分必须用 UNION ALL 连接,且递归引用只能出现在 FROM 子句中,别名必须和 CTE 名一致:

WITH RECURSIVE org_tree AS (
  SELECT id, name, manager_id, 1 AS level
  FROM employees
  WHERE manager_id IS NULL  -- 锚点:顶层
  UNION ALL
  SELECT e.id, e.name, e.manager_id, ot.level + 1
  FROM employees e
  INNER JOIN org_tree ot ON e.manager_id = ot.id  -- ✅ 正确:引用自身别名
)
SELECT * FROM org_tree;

注意:MySQL 默认递归深度限制为 100,超限报 ERROR 3636 (HY000);PostgreSQL 是 stack depth limit exceeded。调高前先确认逻辑是否真需要那么深。

真正容易被忽略的点是:CTE 本身不物化——多数引擎只是语法重写,性能未必提升。你花十分钟优化命名和拆分逻辑,换来的是别人三秒看懂、两分钟改对,这才是 WITH 的真实价值所在。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

3743

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

791

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

969

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5501

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2503

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5500

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7161

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

970

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

852

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.1万人学习