递归查询与树形结构
- 简介
关系数型据库(如Oracle)的信息通常存储在一个或多个表中。
为表示现实世界中的有多重级联关系的概念,通常我们会把这些对象存储于同一张表,并通过一组字段(Field)表达它们之间的隶属关系。
譬如常见的部门信息:
tb_dept(dept_id,dept_name,parent_id)
名称 | 含义 |
dept_id | 部门ID |
dept_name | 名称 |
parent_id | 隶属部门ID |
我们经常需要分析这些数据,并把结果组织成树形结构加以表示。
针对这一问题,Oracle提供了一个查询树形数据的语法。
START WITH...CONNECT BY
该子句是一个递归查询,它可以查询树中某个节点的所有子节点,并把结果按级展开一个树的形式,列出某节点所处的层,便于我们维护和处理。示例如下:
- 示例
-- 创建实例表
DROP TABLE test_dept;
CREATE TABLE test_dept
(
dept_id VARCHAR2(20),
dept_name VARCHAR2(40),
parent_id VARCHAR2(20)
);
-- 插入测试数据
INSERT INTO test_dept VALUES('0','dept',NULL);
INSERT INTO test_dept VALUES('1','dept1','0');
INSERT INTO test_dept VALUES('11','dept11','1');
INSERT INTO test_dept VALUES('12','dept12','1');
INSERT INTO test_dept VALUES('2','dept2','0');
INSERT INTO test_dept VALUES('21','dept21','2');
INSERT INTO test_dept VALUES('211','dept211','21');
INSERT INTO test_dept VALUES('212','dept212','21');
INSERT INTO test_dept VALUES('22','dept22','2'); 从Root往树末梢递归 SELECT dept_id,
dept_name,
level
FROM test_dept
START WITH dept_id ='0'
CONNECT BY prior dept_id=parent_id;
从末梢往树Root递归 SELECT dept_id,
dept_name,
level
FROM test_dept
START WITH dept_id ='212'
CONNECT BY prior parent_id = dept_id;
详解
CONNECT BY 是结构化查询中用到的,其基本语法是: SELECT ... FROM tablename START BY cond1
CONNECT BY cond2
WHERE cond3;
简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段:id, parentid那么通过表示每一条记录的parent是谁,就可以形成一个树状结构。用上述语法的查询可以取得这棵树的所有记录。 其中:- COND1是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。
- COND2是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR ID=PRAENTID就是说上一条记录的ID是本条记录的PRAENTID,即本记录的父亲是上一条记录。
- COND3是过滤条件,用于对返回的所有记录进行过滤。
PRIOR和START WITH关键字是可选项- 总结
START WITH...CONNECT BY 理解此语句的关键在与CONNECT BY和PRIOR。 前者决定连接条件,后者决定递归运行的方向。 例子一:连接条件是dept_id = parent_id,方向是parent_id --> dept_id(往下)。 SELECT dept_id,
dept_name,
level
FROM test_dept
START WITH dept_id ='0'
CONNECT BY prior dept_id=parent_id; 例子二:连接条件是dept_id = parent_id,方向是dept_id --> parent_id(往上)。 SELECT dept_id,
dept_name,
level
FROM test_dept
START WITH dept_id ='212'
CONNECT BY prior parent_id = dept_id;