mysql 8.0.1+才支持with recursive,必须含锚点查询、union all及显式递归引用;列数类型需一致,须设终止条件并防环引用,递归深度默认限1000层。

MySQL 8.0 支持 WITH RECURSIVE,但必须确保你用的是 8.0.1 或更高版本;低于这个版本会直接报错 ERROR 1064 (42000),提示语法错误。
递归CTE的结构必须包含 anchor + UNION ALL + recursive reference
缺一不可。anchor(初始查询)负责提供第一层数据,UNION ALL 是强制要求(不能用 UNION DISTINCT),而递归部分必须显式引用 CTE 自身名称,且只能在 FROM 子句中出现一次。
- anchor 查询不能引用 CTE 名称,否则报错
Unknown table 'cte_name' in field list - 递归部分若写成子查询(比如
WHERE id IN (SELECT ... FROM cte_name)),会触发Recursive reference to CTE 'cte_name' is not allowed in subquery -
UNION ALL左右两侧列数、类型要严格一致;常见翻车点是 anchor 返回INT,递归部分算出BIGINT,导致隐式转换失败或结果截断
查树形结构时,必须加终止条件,否则无限循环
MySQL 默认递归深度上限是 1000 层(由系统变量 cte_max_recursion_depth 控制),超限会报错 ERROR 3636 (HY000): Recursive query aborted after 1000 iterations。这不是性能问题,是硬性熔断机制。
- 在递归部分的
WHERE中显式限制层级,例如level ,比依赖默认值更可靠 - 业务上要预防环状引用(比如 A → B → C → A),否则即使加了
level也拦不住;可配合PATH字段记录已遍历 ID 列表,用FIND_IN_SET(id, path) = 0避免重复 - 如果只需要某节点的所有祖先,anchor 应从该节点开始,递归方向是向上查
parent_id;反之查所有后代,则 anchor 是父节点,递归方向是向下查id = parent_id
LEFT JOIN 不能把递归CTE放右边,否则语法报错
这是 MySQL 特有的限制:WITH RECURSIVE cte AS (...) SELECT * FROM other_table LEFT JOIN cte ON ... 会直接失败,提示 ERROR 1109 (42S02): Unknown table 'cte' in MULTI DELETE/UPDATE/JOIN。
- 正确写法是把 CTE 放在
FROM最左侧,或改用INNER JOIN(CTE 必须有匹配行) - 需要补 NULL 行时,可先让 CTE 输出完整结果,再用
LEFT JOIN关联其他表——顺序不能颠倒 - 多 CTE 场景下,后定义的 CTE 可以引用前面的 CTE,但不能形成循环依赖,例如
cte1 AS (...), cte2 AS (SELECT * FROM cte1), cte1 AS (...)是非法的
真正麻烦的不是语法写不对,而是递归逻辑和业务层级理解错位:anchor 选错起点、递归方向反了、漏掉环检测,这些都不会立刻报错,但返回的数据是静默错误的——看起来“跑通了”,实际漏数据或重复计算。上线前务必用小规模闭环数据验证路径完整性。











