怎么在SQL中对自关联表进行多级分组汇总查询?

小枫君_6390

小枫君_6390

2026-09-01

481人浏览

原创

自关联表多级分组汇总需先构建层级关系再聚合,不能直接用group by;应使用递归cte(如with recursive)展开层级并按level或path分组,或用多次left join兼容旧版本,关键索引为(manager_id, id)。

怎么在sql中对自关联表进行多级分组汇总查询?

什么是自关联表的多级分组汇总

自关联表(比如员工表 employees 中用 manager_id 指向自身)做多级分组汇总,本质是先构建层级关系(如部门 → 小组 → 个人),再按层级路径聚合数据。直接用 GROUP BY 无法表达“上级汇总包含下级”的递归逻辑,必须借助递归 CTE 或连接展开。

用递归 CTE 展开层级并分组

PostgreSQL、SQL Server、MySQL 8.0+ 支持 WITH RECURSIVE,这是最清晰的方式:先定义根节点(如 manager_id IS NULL),再逐层 JOIN 自身,生成带层级深度和路径的中间结果。

常见错误是漏掉终止条件或未限制递归深度,导致无限循环或超时。建议始终加上 LEVEL 类似保护。

  • 递归查询中,level 字段必须显式累加(如 parent.level + 1),不能依赖外部变量
  • 汇总时对 path(如 '/1/5/12')或 level 分组,而非原始 id
  • 若需统计每级人数和平均薪资,SELECT level, COUNT(*), AVG(salary) 配合 GROUP BY level
WITH RECURSIVE emp_tree AS (
  SELECT id, name, manager_id, salary, 1 AS level, CAST(id AS VARCHAR) AS path
  FROM employees WHERE manager_id IS NULL
  UNION ALL
  SELECT e.id, e.name, e.manager_id, e.salary, t.level + 1, t.path || '/' || e.id
  FROM employees e
  INNER JOIN emp_tree t ON e.manager_id = t.id
  WHERE t.level 

<h3>用多次 LEFT JOIN 展开固定层级(兼容老版本)</h3>
<p>当数据库不支持递归 CTE(如 MySQL 5.7、SQLite),只能手动 JOIN 多次。例如查三级结构(CEO → 部门总监 → 组长 → 员工),需 JOIN 三次 <code>employees</code> 表,分别别名为 <code>e1</code>, <code>e2</code>, <code>e3</code>。</p><div class="aritcle_card flexRow artxards">
											<div class="artcardd flexRow">
												<a class="aritcle_card_img" rel="nofollow" href="/ai/1807" title="故事AI绘图神器"><img
														src="https://img.php.cn/upload/ai_manual/000/969/633/68b6cc9c77119274.png" alt="故事AI绘图神器" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
												<div class="aritcle_card_info flexColumn">
													<a rel="nofollow" href="/ai/1807" title="故事AI绘图神器" class="overflowclass">故事AI绘图神器</a>
													<p class="overflowclass">一款面向故事和图文视频创作的AI工具,可以根据文本内容生成相关画面并形成连续视觉内容,适合快速制作故事类作品。</p>
												</div>
												<a rel="nofollow" href="/ai/1807" title="故事AI绘图神器" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
												</a>
											</div>
										</div>
<p>容易踩的坑是 JOIN 条件写错(如把 <code>e2.manager_id = e1.id</code> 写成 <code>e2.id = e1.manager_id</code>),导致层级倒置;另外 NULL 值处理不当时,<code>GROUP BY e1.id</code> 会漏掉无下属的叶子节点。</p>
  • 每一级 JOIN 都要确保方向一致:下属.manager_id = 上级.id
  • 用 COALESCE(e3.salary, e2.salary, e1.salary) 取实际薪资,避免因层级缺失引入 NULL
  • 若只关心“部门级汇总”,GROUP BY e2.id(假设 e2 是部门总监),但需加 WHERE e2.id IS NOT NULL 过滤掉无部门归属的记录

性能与索引关键点

自关联层级查询性能极易劣化。没有索引时,每次递归或 JOIN 都可能触发全表扫描。核心索引不是主键,而是 (manager_id, id) 联合索引 —— 它能加速“找所有下属”这个最频繁的操作。

另一个易忽略点是路径字符串(如 '/1/5/12')无法走索引,所以不要在递归 CTE 的 WHERE 中对 path LIKE '/1/%' 做过滤;应改用 manager_id IN (SELECT id FROM emp_tree WHERE ...) 等可利用索引的方式。

层级超过 10 层时,即使有索引,递归 CTE 也可能变慢,这时得考虑预计算路径字段并建索引,或者改用应用层分批拉取。

相关文章

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

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

下载

相关标签:

sql语句 sql优化 sql创建

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系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

4343

8

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

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

2023.10.27

911

4

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

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

2024.02.23

1129

5

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

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

2024.03.06

6281

10

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

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

2024.03.06

3103

4

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

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

2024.04.07

6260

11

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

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

2024.04.29

8481

6

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

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

2024.04.29

1150

5

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

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

2024.04.29

1012

5

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PDO数据库抽象层
PDO数据库抽象层

共7课时 | 3.3万人学习

SQL优化与排查(MySQL版)
SQL优化与排查(MySQL版)

共26课时 | 3.3万人学习