必须用WITH RECURSIVE CTE计算树深度,因关联子查询无法动态展开任意深度且旧版MySQL不支持多层相关子查询;CTE要求anchor与recursive字段数量、顺序、类型严格一致,连接条件为o.parent_id = t.id,深度查询需在anchor中限定起点并用MAX(level)。
关联子查询无法可靠计算树深度
直接用关联子查询(比如 SELECT ... (SELECT COUNT(*) FROM ...) 嵌套)算节点深度,基本不可行。它只能查固定层数的祖先,没法动态展开任意深度;一旦树深超过手写嵌套层数,结果就漏掉;更严重的是,MySQL 5.7 及更早版本不支持多层相关子查询在 FROM 中引用外层,会报错 Unknown column 't1.id' in 'where clause'。
必须用 WITH RECURSIVE CTE,且 anchor 和 recursive 要对齐
真正能通用、可读、可控的方式是递归 CTE。关键不是“能不能写”,而是两部分列定义必须严格一致:
-
anchor查询(根节点)和recursive查询的字段数量、顺序、类型必须完全匹配,否则 PostgreSQL 报错recursive query "tree" column "level" has type integer but expression has type text - 连接条件必须是
o.parent_id = t.id(子表的父 ID 指向上一层的 ID),写反成o.id = t.parent_id就会跳层或死循环 - MySQL 默认递归深度上限是 1000,超深组织树要提前执行
SET SESSION cte_max_recursion_depth = 5000
查单个节点的子树深度:WHERE 条件必须放在递归内部
如果只关心“部门 ID=5 下面最深有多少层”,不能把 WHERE id = 5 放在最终 SELECT 后——那样会先遍历整棵树再过滤,性能爆炸。正确做法是:
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
- anchor 部分锁定起点:
WHERE id = 5 - recursive 部分保持
JOIN ... ON o.parent_id = t.id - 最后用
SELECT MAX(level)而不是SELECT *
示例:
WITH RECURSIVE tree AS ( SELECT id, parent_id, 1 AS level FROM organization WHERE id = 5 UNION ALL SELECT o.id, o.parent_id, t.level + 1 FROM organization o INNER JOIN tree t ON o.parent_id = t.id ) SELECT MAX(level) AS depth FROM tree;
层级显示时 level 字段容易被误用
level 是从 anchor 开始计数的,不是全局深度。比如根节点 parent_id IS NULL 的 level = 1,它的直接子节点是 level = 2。如果你需要“从根算起的绝对深度”,anchor 必须从根开始;如果只需要“某节点向下延伸几层”,anchor 就从该节点开始。别混用两种语义,也别试图用 ROW_NUMBER() 或 RANK() 替代 level——它们在递归 CTE 里不被允许。