层次查询
说明
层次查询是一种强大的查询功能,它允许用户按照数据之间的层级关系来检索和展示信息。在现实世界中,很多数据都存在层次结构,比如组织架构(部门和员工)、产品分类(类别和子类别)、多级菜单等。通过层次查询,可以方便地从数据库中提取出这种层次化的数据,并以树形结构或其他合适的格式呈现出来,从而更直观地展现数据之间的层级关系,帮助用户更好地理解和分析数据。例如,可以查询出一个公司从最高层领导到各级下属员工的完整组织架构,或者从顶级产品类别到具体的子产品类别等。
层次查询支持兼容Oracle层次查询中的CONNECT BY与START WITH语句。其中:
- START WITH指定根行,即查询的起始点。
- CONNECT BY后指定父子关系,即迭代条件,用于定义层次结构。
1、循环处理
- NOCYCLE关键字用于表明忽略循环。
- 如果递归过程中发现存在循环,即存在节点既是祖先节点又是子节点的情况:
- 如果不指定NOCYCLE关键字,则递归到循环时会报错。
- 如果指定NOCYCLE,则不会继续往下递归。
2、同层节点排序
层次查询支持在ORDER BY后面加SIBLINGS指定层次查询同层节点的顺序。目前仅实现可以在 ORDER BY 之间加SIBLINGS关键字。
3、层次查询的伪列
层次查询的伪列仅能在层次查询中使用,包括以下三个:
- CONNECT_BY_ISCYCLE 伪列:如果当前行有一个子项,而这个子项也是当前行的祖先,则 CONNECT_BY_ISCYCLE 返回1,表示存在循环;否则返回 0。
- CONNECT_BY_ISLEAF伪列:如果当前的行是整个树的叶子节点,返回 1,否则返回 0。这个信息可以指示当前行是否还可以继续扩展。
- LEVEL伪列:LEVEL表示当前行的层级,从1开始。根行的LEVEL为1,其子节点为2,子子节点为3,以此类推。
4、操作符支持
- PRIOR操作符:PRIOR是一元运算符,它引用当前行的父行来计算紧随其后的表达式,经常出现在等式运算符比较列中。它可以位于运算符的任意一侧。
- CONNECT_BY_ROOT 操作符:该操作符仅能在层次查询中使用。当你使用该操作符作用于一个列时,返回的是根行的数据。
5、SYS_CONNECT_BY_PATH函数
层次查询还支持SYS_CONNECT_BY_PATH函数,该函数只能在层次查询中使用。它返回从根行到本行指定列的路径,路径分隔符使用char来指定,返回值是 varchar2类型。
示例
CREATE TABLE employees (
employee_id NUMBER(6),
last_name VARCHAR2(25),
manager_id NUMBER(6)
);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (100, ‘King’, NULL);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (101, ‘Kochhar’, 100);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (102, ‘De Haan’, 100);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (103, ‘Hunold’, 102);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (104, ‘Ernst’, 103);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (105, ‘Austin’, 103);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (106, ‘Pataballa’, 103);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (107, ‘Lorentz’, 103);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (108, ‘Greenberg’, 101);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (109, ‘Faviet’, 108);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (110, ‘Chen’, 108);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (111, ‘Sciarra’, 108);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (112, ‘Urman’, 108);
INSERT INTO employees (employee_id, last_name, manager_id) VALUES (113, ‘Popp’, 108);
示例查询
1、 使用 LEVEL 伪列
查询每个员工及其层级深度:
SELECT employee_id, last_name, manager_id, LEVEL, SYS_CONNECT_BY_PATH(last_name, ‘/‘) “Path”
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
2、 使用 CONNECT_BY_ISLEAF 伪列
查询每个员工是否是叶子节点:
SELECT employee_id, last_name, manager_id, LEVEL, CONNECT_BY_ISLEAF AS “IsLeaf”
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;