如何在SQL中使用嵌套查询实现基于父级的递归统计_通过路径查找子查询

秋芳君_2466

秋芳君_2466

2026-05-06

884人浏览

原创

不能直接用with recursive,因mysql 5.7等旧版本不支持,且路径字段需字符串匹配模拟层级;应改用自连接+like前缀匹配(如c2.path like concat(c1.path, '%')),并统一路径格式、添加深度校验防误匹配。

如何在sql中使用嵌套查询实现基于父级的递归统计_通过路径查找子查询

为什么不能直接用 WITH RECURSIVE 就完事?

很多用户一看到“递归统计”就立刻查 WITH RECURSIVE,但实际中常卡在路径解析这步:比如字段存的是 /1/5/12/ 这种字符串路径,数据库没开递归支持(如 MySQL 5.7),或业务要求兼容旧版本。这时候硬上 CTE 反而报错 ERROR 1142 (42000): WITH RECURSIVE is not allowed in this context,得换路子。

核心思路是:不依赖递归语法,改用自连接 + 字符串匹配模拟层级关系。

  • parent_id 字段缺失或不可靠时,path 是唯一可信的层级依据
  • MySQL 5.7+、PostgreSQL 9.6+、SQL Server 2016+ 都能用 LIKE 或正则做路径前缀匹配
  • 注意路径分隔符必须统一(推荐用 /,避免 \ 引发转义问题)

用 LIKE 匹配父路径并统计子节点数量

假设表 categories 有字段 id、name、path(值如 /1/、/1/5/、/1/5/12/),要统计每个节点下有多少子孙(含自己):

SELECT 
  c1.id,
  c1.name,
  c1.path,
  COUNT(c2.id) AS descendant_count
FROM categories c1
LEFT JOIN categories c2 ON c2.path LIKE CONCAT(c1.path, '%')
GROUP BY c1.id, c1.name, c1.path;

关键点:

  • CONCAT(c1.path, '%') 确保匹配所有以该路径开头的子孙,比如 /1/ 能命中 /1/5/ 和 /1/5/12/
  • 必须用 LEFT JOIN,否则根节点(如 /1/)若无子节点会直接被过滤掉
  • 如果路径末尾不带斜杠(如存成 /1),需改用 c2.path = c1.path OR c2.path LIKE CONCAT(c1.path, '/%')

排除自身、只算严格子节点的写法

上面的统计包含节点自己,若只要“子节点数量”(不含自身),得加条件过滤:

SELECT 
  c1.id,
  c1.name,
  c1.path,
  COUNT(c2.id) AS children_count
FROM categories c1
LEFT JOIN categories c2 
  ON c2.path LIKE CONCAT(c1.path, '%') 
  AND c2.path != c1.path  -- 排除自己
GROUP BY c1.id, c1.name, c1.path;

常见陷阱:

  • 漏掉 c2.path != c1.path → 每个节点至少算 1(自己),结果全错
  • 路径格式不规范:如 /1/5 和 /1/5/ 并存,会导致 /1/5 错误匹配 /1/50/(因为 '/1/5%' LIKE '/1/5/' 成立)→ 务必统一结尾加斜杠
  • 索引失效:LIKE 以通配符开头(如 '%1/5/')无法走索引;但 CONCAT(c1.path, '%') 是前缀匹配,只要 path 字段有 B-tree 索引就能加速

路径深度不确定时,如何避免跨级误匹配?

当路径结构松散(如允许 /1/5/12/ 和 /1/50/12/ 共存),单纯用 LIKE 可能导致 /1/5/ 错把 /1/50/12/ 当作子节点(因为 '/1/50/12/' LIKE '/1/5/%' 为真)。这时得靠路径段数约束:

SELECT 
  c1.id,
  c1.name,
  COUNT(c2.id) AS safe_children_count
FROM categories c1
LEFT JOIN categories c2 
  ON c2.path LIKE CONCAT(c1.path, '%')
  AND (LENGTH(c2.path) - LENGTH(REPLACE(c2.path, '/', ''))) 
     > (LENGTH(c1.path) - LENGTH(REPLACE(c1.path, '/', '')))
GROUP BY c1.id, c1.name;

说明:

  • LENGTH(path) - LENGTH(REPLACE(path, '/', '')) 算出路径中 / 的个数,即深度(/1/ 深度为 2,/1/5/ 为 3)
  • 要求子节点深度严格大于父节点,排除同级或父级干扰
  • 性能代价:每行都算两次字符串长度,大数据量时建议提前把深度存为冗余字段 depth,然后直接 c2.depth > c1.depth

真正麻烦的不是写法,而是路径数据本身是否干净——如果已有数据混着 /1、/1/、/1//5/ 几种格式,先清洗再统计,比硬写 SQL 更重要。

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

3803

8

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

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

2023.10.27

811

4

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

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

2024.02.23

989

5

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

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

2024.03.06

5621

10

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

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

2024.03.06

2583

4

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

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

2024.04.07

5600

11

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

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

2024.04.29

7361

6

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

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

2024.04.29

1010

5

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

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

2024.04.29

872

5

热门下载

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

精品课程

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

共6课时 | 54.6万人学习

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

共89课时 | 133.2万人学习