递归查询与树形结构

  • 简介
关系数型据库(如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是谁,就可以形成一个树状结构。用上述语法的查询可以取得这棵树的所有记录。
 
其中:
  1. COND1是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。
  2. COND2是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR ID=PRAENTID就是说上一条记录的ID是本条记录的PRAENTID,即本记录的父亲是上一条记录。
  3. COND3是过滤条件,用于对返回的所有记录进行过滤。
PRIOR和START WITH关键字是可选项
  • 总结
START WITH...CONNECT BY
 
理解此语句的关键在与CONNECT BYPRIOR
 
前者决定连接条件,后者决定递归运行的方向。
 
例子一:连接条件是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;




posted @ 2011-11-25 13:53  __BSD__  阅读(475)  评论(0编辑  收藏  举报