2023-10-25 09:52:25
SQL 递归查询通过公共表表达式(CTE)实现,主要用于处理具有自引用关系的数据(如树形结构、组织层级等)。以下是详细步骤和示例:
1. 递归查询的核心步骤确定递归关系识别表中表示自引用的列(如 ReportsTo 指向同表的 EmployeeID)。
编写递归 CTE使用 WITH 子句定义 CTE,结构如下:
WITH RECURSIVE CTE名称 AS ( -- 基础查询(起点) SELECT 列名 FROM 表名 WHERE 初始条件 UNION ALL -- 递归部分(引用CTE自身) SELECT 列名 FROM 表名 JOIN CTE名称 ON 递归关联条件)SELECT * FROM CTE名称;指定终止条件递归会在 UNION ALL 的子查询中自动停止,当无法匹配新数据时结束(无需显式条件,但可通过 WHERE 限制深度)。
假设 Employee 表结构如下:
需求:查找所有直接或间接向经理ID=10汇报的员工。
WITH RECURSIVE EmployeeHierarchy AS ( -- 基础查询:从经理10开始 SELECT EmployeeID, ReportsTo, Name, 1 AS Level FROM Employee WHERE EmployeeID = 10 UNION ALL -- 递归查询:查找下属 SELECT e.EmployeeID, e.ReportsTo, e.Name, eh.Level + 1 FROM Employee e JOIN EmployeeHierarchy eh ON e.ReportsTo = eh.EmployeeID)SELECT EmployeeID, Name, LevelFROM EmployeeHierarchyWHERE EmployeeID != 10; -- 排除经理自身(可选)结果说明:
RECURSIVE 关键字部分数据库(如 PostgreSQL、SQLite)要求显式声明 RECURSIVE,而 SQL Server 和 Oracle 默认支持递归 CTE。
避免无限循环确保递归关系最终会终止(如树形结构无环)。若存在环路,可使用 WHERE Level < 最大深度 限制。
性能优化递归查询可能消耗大量资源,建议在递归列上建立索引。
查询文件夹层级
WITH RECURSIVE FolderTree AS ( SELECT id, name, parent_id FROM folders WHERE id = 1 UNION ALL SELECT f.id, f.name, f.parent_id FROM folders f JOIN FolderTree ft ON f.parent_id = ft.id)SELECT * FROM FolderTree;计算路径(如组织架构全路径)
WITH RECURSIVE PathCTE AS ( SELECT EmployeeID, Name, CAST(Name AS VARCHAR(1000)) AS Path FROM Employee WHERE ReportsTo IS NULL UNION ALL SELECT e.EmployeeID, e.Name, CONCAT(p.Path, ' -> ', e.Name) FROM Employee e JOIN PathCTE p ON e.ReportsTo = p.EmployeeID)SELECT * FROM PathCTE;通过递归 CTE,SQL 能够高效处理层级数据,简化复杂查询逻辑。实际使用时需结合业务需求调整终止条件和结果过滤。