SQL Server递归CTE必须用WITH+UNION ALL,不能用WITH RECURSIVE;WITH须为分支首条语句;OPTION(MAXRECURSION n)须加在最终SELECT末尾;必须用UNION ALL而非UNION以防数据丢失;锚成员与递归成员列定义须严格一致;连接条件错误会导致无限递归。

SQL Server 存储过程中处理层级数据,必须用 WITH + UNION ALL 构建递归 CTE,不能写 WITH RECURSIVE——否则直接报错 Incorrect syntax near the keyword 'RECURSIVE'。
SQL Server 存储过程里 WITH 必须是分支第一条语句
常见错误是把 WITH 套在 IF 或 BEGIN...END 里,但前面还有别的语句(比如先 SELECT 再 WITH)。SQL Server 要求 WITH 是该作用域内第一个可执行关键字。
- 错:在
IF @rootId IS NOT NULL BEGIN SELECT 1; WITH Tree AS () ... END——SELECT挡在前面,语法报错 - 对:把整个 CTE 块提前到分支开头,例如
IF @rootId IS NOT NULL BEGIN WITH Tree AS () SELECT * FROM Tree OPTION (MAXRECURSION 500); END - 如果要根据条件走不同树结构(比如按部门类型),建议拆成多个独立
WITH块,别硬塞进一个 CTE 里做CASE分支判断
递归深度超限会直接中断,不是超时
OPTION (MAXRECURSION n) 必须加在最终 SELECT、INSERT 等语句末尾,不能写在 CTE 定义里。默认 100 层,查五级以上组织架构很容易触发 The maximum recursion 100 has been exhausted,此时不会返回任何结果,会话直接中断。
-
OPTION (MAXRECURSION 0)表示不限制,但生产环境禁用——循环引用或脏数据会导致内存耗尽、会话卡死 - 建议把
@maxRecursion设为存储过程输入参数,由调用方控制,比如“最多展开 6 级”就传6 - 执行计划里如果看到
Sort算子出现在递归分支中,大概率是误用了UNION而非UNION ALL
UNION ALL 不是性能优化,是行为刚性约束
递归 CTE 中必须用 UNION ALL,不是为了性能,是语义和行为刚性约束。SQL Server 虽不报语法错,但用 UNION 会触发去重逻辑,导致同名节点被合并,整层数据丢失。
- 假设员工表里有两个
name = '张工'的下属,用UNION后第二层只剩一个,“树”就断了 - 递归本质是“逐层追加”,不是“合并去重”,
UNION ALL才符合这一语义 - 锚成员和递归成员的列数、类型、顺序必须严格一致,否则运行时报错
连接条件写反或漏掉,会无限循环
真正容易被忽略的是:锚成员必须能明确终止(比如 WHERE id = @rootId),而递归成员的连接条件(如 ON e.manager_id = s.id)一旦写反或漏掉,就会无限循环——这时候 MAXRECURSION 是最后一道防线,不是替代严谨逻辑的补丁。
比如查下属时该写 ON child.manager_id = parent.id,写成 ON child.id = parent.manager_id 就会错位匹配,触发无效递归。这种错误不会立刻报错,而是等跑满层数后才中断,排查成本高。

















