You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 22:45:05