sql server递归查询必须用with+union all,禁用recursive;with须为分支首条语句;多条件宜分多个cte;maxrecursion需设于最终select末尾,默认100层易超限;union会导致数据丢失,必须用union all;锚与递归成员列结构须严格一致,连接条件错误将引发无限循环。

SQL Server 存储过程中实现组织架构递归查询,必须用 WITH + UNION ALL 结构,不能写 WITH RECURSIVE——否则直接报错 Incorrect syntax near the keyword 'RECURSIVE'。
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 里做分支判断
递归深度超限就卡死,不是超时而是主动终止
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才符合这一语义 - 锚成员和递归成员的列数、类型、顺序必须严格一致,否则运行时报错
真正容易被忽略的是:递归 CTE 的锚成员必须能明确终止(比如 WHERE id = @rootId),而递归成员的连接条件(如 ON e.manager_id = s.id)一旦写反或漏掉,就会无限循环——这时候 MAXRECURSION 是最后一道防线,不是替代严谨逻辑的补丁。











