Oracle 层次查询(Hierarchical Query)
Oracle 层次查询(Hierarchical Query)
适用版本:Oracle Database 8i / 9i / 10g / 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07
1. 概述
层次查询(Hierarchical Query) 用于查询树形结构数据[1]:
典型场景:
- 组织架构
- 物料清单(BOM)
- 评论回复
- 分类层级
2. 基本语法
SELECT ...
FROM table
START WITH condition
CONNECT BY [NOCYCLE] condition
[ORDER SIBLINGS BY column];
3. 基本示例
3.1 组织架构
-- 员工与经理关系
SELECT
employee_id,
last_name,
manager_id,
LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
3.2 字段说明
START WITH:根节点条件CONNECT BY:父子关系PRIOR:父行字段LEVEL:层级(伪列)
4. LEVEL 伪列
4.1 缩进显示
SELECT
LPAD(' ', LEVEL * 2 - 2) || last_name AS name,
LEVEL,
employee_id,
manager_id
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
4.2 过滤层级
-- 仅显示前 3 层
SELECT last_name, LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id
AND LEVEL <= 3;
5. CONNECT_BY_ROOT
5.1 获取根节点
SELECT
last_name,
CONNECT_BY_ROOT last_name AS root_manager,
LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
6. CONNECT_BY_ISLEAF
6.1 判断叶子节点
SELECT
last_name,
CONNECT_BY_ISLEAF AS is_leaf,
LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
-- is_leaf: 1=叶子, 0=非叶子
7. SYS_CONNECT_BY_PATH
7.1 路径
-- 显示完整路径
SELECT
last_name,
SYS_CONNECT_BY_PATH(last_name, ' -> ') AS path,
LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
7.2 输出
King -> King
King -> Jones
King -> Jones -> Scott
King -> Jones -> Scott -> Adams
8. NOCYCLE 与 CONNECT_BY_ISCYCLE
8.1 处理循环
-- 数据有循环时使用 NOCYCLE
SELECT
last_name,
CONNECT_BY_ISCYCLE AS is_cycle,
LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY NOCYCLE PRIOR employee_id = manager_id;
-- is_cycle: 1=有循环, 0=无
9. ORDER SIBLINGS BY
9.1 同级排序
SELECT
LPAD(' ', LEVEL * 2 - 2) || last_name AS name,
salary
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id
ORDER SIBLINGS BY salary DESC;
10. 递归 CTE(11g R2+)
10.1 语法
WITH org_chart (employee_id, last_name, manager_id, lvl, path) AS (
-- 起点
SELECT
employee_id,
last_name,
manager_id,
1 AS lvl,
last_name AS path
FROM employees
WHERE manager_id IS NULL
UNION ALL
-- 递归
SELECT
e.employee_id,
e.last_name,
e.manager_id,
oc.lvl + 1,
oc.path || ' -> ' || e.last_name
FROM employees e
JOIN org_chart oc ON e.manager_id = oc.employee_id
)
SELECT * FROM org_chart ORDER BY path;
10.2 优势
- ANSI 标准
- 灵活
- 支持复杂逻辑
11. 应用场景
11.1 BOM 展开
-- 物料清单
SELECT
LPAD(' ', LEVEL * 2 - 2) || part_name AS part,
quantity,
LEVEL
FROM bom
START WITH parent_id IS NULL
CONNECT BY PRIOR part_id = parent_id;
11.2 子树查询
-- 查询某节点的所有下属
SELECT employee_id, last_name, LEVEL
FROM employees
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id;
11.3 父树查询
-- 查询某员工的所有上级
SELECT employee_id, last_name, LEVEL
FROM employees
START WITH employee_id = 200
CONNECT BY PRIOR manager_id = employee_id;
12. 性能优化
12.1 索引
-- 父子关系列加索引
CREATE INDEX idx_emp_mgr ON employees(manager_id);
CREATE INDEX idx_emp_id ON employees(employee_id);
12.2 限制层级
-- 限制深度
SELECT * FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 5;
12.3 过滤起点
-- 缩小起点范围
SELECT * FROM employees
START WITH manager_id IS NULL AND dept_id = 10
CONNECT BY PRIOR employee_id = manager_id;
13. 常见坑与排错
13.1 ORA-01436: CONNECT BY 循环
修复:
-- 使用 NOCYCLE
SELECT * FROM employees
START WITH manager_id IS NULL
CONNECT BY NOCYCLE PRIOR employee_id = manager_id;
13.2 PRIOR 方向错误
-- 查下属
CONNECT BY PRIOR employee_id = manager_id
-- PRIOR 在父列
-- 查上级
CONNECT BY PRIOR manager_id = employee_id
-- PRIOR 在子列
13.3 WHERE 与 CONNECT BY 顺序
-- 执行顺序:
-- 1. WHERE(过滤所有行)
-- 2. START WITH
-- 3. CONNECT BY
-- 若要在树构建后过滤,用 CONNECT BY 中的条件
13.4 性能差
修复:
-- 1. 加索引
-- 2. 限制层级
-- 3. 缩小起点
-- 4. 使用递归 CTE
14. 最佳实践
- 索引父子列:提升性能
- 限制深度:避免无限递归
- 使用 NOCYCLE:防止循环错误
- ORDER SIBLINGS BY:保持层级顺序
- LEVEL 控制缩进:清晰显示
- SYS_CONNECT_BY_PATH:路径展示
- 复杂场景用 CTE:灵活
- 测试大数据量:验证性能
- PRIOR 方向正确:父子关系
- 过滤用 CONNECT BY:树构建后过滤
15. 参考资料
[1] Oracle Database SQL Language Reference 19c, “Hierarchical Queries” https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Hierarchical-Queries.html
[2] Oracle Database Data Warehousing Guide 19c, “Recursive WITH Clause” https://docs.oracle.com/en/database/oracle/oracle-database/19/dwhsg/