postgresql强制要求递归cte必须显式声明with recursive,且非递归项与递归项间须用union all连接;mysql无maxrecursion机制,依赖全局cte_max_recursion_depth限制;sql server严格校验锚点与递归项的列顺序、类型及空值性。

PostgreSQL 里写递归 CTE 必须加 RECURSIVE 关键字
不加就报错,不是可选语法糖。PostgreSQL 强制要求显式声明 WITH RECURSIVE,哪怕只有一层递归调用也得写。这是它和 SQL 标准对齐的体现,但和其他数据库(比如 SQL Server、Oracle)的隐式递归逻辑不同。
常见错误现象:ERROR: invalid reference to FROM-clause entry for table "t" 或更直白的 ERROR: recursive query "t" does not have the form non-recursive-term UNION [ALL] recursive-term——往往就是漏了 RECURSIVE,导致解析器根本没启用递归模式。
- 必须写成
WITH RECURSIVE t AS (...),不能省略RECURSIVE - 非递归部分(anchor member)和递归部分(recursive member)之间必须用
UNION ALL(或UNION),不能用UNION DISTINCT或逗号分隔 - 递归引用自身时,只能出现在
FROM子句中,不能在WHERE或SELECT里直接当表名用(比如SELECT * FROM t WHERE id IN (SELECT parent_id FROM t)是非法的)
MySQL 8.0+ 的递归 CTE 不支持 MAXRECURSION 限制
SQL Server 有 OPTION (MAXRECURSION n) 控制深度,MySQL 完全没有这个机制。一旦递归失控,要么超内存崩溃,要么被 cte_max_recursion_depth 全局变量硬性截断(默认 1000),且这个值不能在语句级覆盖。
使用场景:处理组织架构、评论回复链、路径遍历等天然可能成环的数据时,MySQL 更容易因意外循环触发 ERROR 3636 (HY000): Recursive query aborted after 1000 iterations。
- 检查数据是否有环,靠应用层预处理或加
PATH数组记录已访问 ID(用JSON_CONTAINS判断) - 调大全局变量需重启或 SUPER 权限:
SET GLOBAL cte_max_recursion_depth = 5000,但治标不治本 -
UNION ALL是唯一允许的联合方式,UNION会隐式去重但不解决环问题,还拖慢性能
SQL Server 的递归 CTE 要小心锚点与递归项的列顺序和类型严格匹配
SQL Server 对 WITH 后面的列别名列表和两个子查询的实际 SELECT 字段顺序、类型、空值性(nullability)都做逐位校验。差一点就报 Types don't match between the anchor and the recursive part。
参数差异:即使你用 CAST 或 CONVERT 显式转了类型,如果锚点返回 INT,递归项返回 TINYINT,仍会失败——SQL Server 认为它们不是“完全兼容类型”。
- 统一用
CAST(... AS BIGINT)或CONVERT(BIGINT, ...)确保数值宽度一致 - 字符串字段必须显式指定长度,比如
CAST('' AS VARCHAR(255)),不能只写CAST('' AS VARCHAR) - 锚点中用
NULL占位的字段,要配合IS NULL检查逻辑,否则递归项返回非空值时类型推导会崩
所有数据库里递归 CTE 的性能都依赖索引和终止条件设计
递归不是魔法,它本质是迭代执行多个 JOIN。每轮递归都会重新扫描上一轮结果集关联的基表,如果没有合适索引,复杂度接近 O(n²)。
容易踩的坑:用 LIKE '%xxx%' 或函数包装连接字段(如 UPPER(parent_name))会让索引失效,递归层级一深,查询直接卡死。
- 确保递归 JOIN 的字段(比如
parent_id→id)上有索引,最好是复合索引覆盖常用过滤条件 - 尽早用
WHERE剪枝,比如限制最大深度:WHERE level (需在递归项里定义并传递 <code>level) - 避免在递归项里做聚合、排序或子查询,这些操作无法下推,会在每轮重复执行
递归深度超过几十层时,就得怀疑是不是该换图算法或物化路径了——CTE 不是万能树遍历工具,它只是 SQL 里最方便的起点。










