如何编写SQL对树形Category表每个节点的所有后代值执行SUM求和
我们先统一假设你的Category表基础字段为id(节点唯一标识)、name(分类名)、parent_id(父节点ID,根节点的parent_id为NULL或0)、value(当前节点存储的待汇总数值)。
方案1:递归CTE(主流数据库通用)
MySQL8.0+、PostgreSQL、SQL Server、Oracle等主流数据库都支持递归CTE语法,不需要修改表结构,实现简单:
WITH RECURSIVE category_hierarchy AS ( -- 锚点:每个节点自身作为汇总的根节点 SELECT id AS root_id, id, value FROM Category UNION ALL -- 递归关联所有子节点,根节点保持不变 SELECT ch.root_id, c.id, c.value FROM category_hierarchy ch INNER JOIN Category c ON ch.id = c.parent_id ) SELECT c.id, c.name, c.parent_id, c.value, SUM(ch.value) AS sum_value FROM Category c LEFT JOIN category_hierarchy ch ON c.id = ch.root_id GROUP BY c.id, c.name, c.parent_id, c.value ORDER BY c.id;
逻辑说明:递归CTE会生成「根节点ID - 下属所有节点(含自身)ID - 节点值」的映射关系,最后按根节点分组求和即可得到每个节点的汇总值。
方案2:路径枚举法(兼容旧版本数据库,性能更高)
如果用的是不支持递归CTE的低版本数据库,或者追求更高的查询性能,可以给Category表加一个path字段,存储每个节点的层级路径,比如根节点Cat1的path存/1/,子节点Cat1.1的path存/1/2/,以此类推,查询语句如下:
SELECT c.id, c.name, c.parent_id, c.value, SUM(c2.value) AS sum_value FROM Category c LEFT JOIN Category c2 ON c2.path LIKE CONCAT(c.path, '%') GROUP BY c.id, c.name, c.parent_id, c.value
这个方案在path字段加前缀索引后,查询效率比递归CTE更高,适合层级不深、查询频率高的场景。
性能优化建议
- 递归CTE方案请务必给
parent_id字段加普通索引,大幅降低递归关联的耗时 - 路径枚举方案给
path字段加前缀索引,避免全表扫描 - 如果数据量极大、更新频率低,建议直接把
sum_value作为冗余字段存在表中,节点新增/修改时触发更新,查询时直接读取即可。
内容的提问来源于stack exchange,提问作者cuongle
相关产品推荐
相关产品推荐

