码迷,mamicode.com
首页 > 其他好文 > 详细

start with ... connect by 递归查询

时间:2019-03-06 00:35:22      阅读:226      评论:0      收藏:0      [点我收藏+]

标签:role   五步   evel   key   语法   取出   rom   expr   分数   

语法

start with ... connect by语法:

select ... from tablename 
start with 条件1 
connect by prior 条件2 
where 条件3

例如:

select * from table
start with org_id = '***'
connect by prior org_id = parent_id;

简介

简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段:
org_id,parent_id那么通过表示每一条记录的parent是谁,就可以形成一个树状结构。

用上述语法的查询可以取得这棵树的所有记录。
其中:
? 条件1 是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。
? 条件2 是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR org_id = parent_id;就是说上一条记录的org_id 是本条记录的parent_id,即本记录的父亲是上一条记录。
? 条件3 是过滤条件,用于对返回的所有记录进行过滤。

简单介绍如下:
? 在扫描树结构表时,需要依此访问树结构的每个节点,一个节点只能访问一次,其访问的步骤如下:
? 第一步:从根节点开始;
? 第二步:访问该节点;
? 第三步:判断该节点有无未被访问的子节点,若有,则转向它最左侧的未被访问的子节,并执行第二步,否则执行第四步;
? 第四步:若该节点为根节点,则访问完毕,否则执行第五步;
? 第五步:返回到该节点的父节点,并执行第三步骤。
? 总之:扫描整个树结构的过程也即是中序遍历树的过程。

查询实例

创建如下表,并插入数据:

create table DEMO (
ID varchar2(10) primary key,
DSC varchar2(100),
PID varchar2(10)
)
--插入几条数据
Insert Into DEMO values ('00001', '中国', '-1');
Insert Into DEMO values ('00011', '陕西', '00001');
Insert Into DEMO values ('00012', '贵州', '00001');
Insert Into DEMO values ('00013', '河南', '00001');
Insert Into DEMO values ('00111', '西安', '00011');
Insert Into DEMO values ('00112', '咸阳', '00011');
Insert Into DEMO values ('00113', '延安', '00011');

树形图如图:

技术图片

自底向上的递归

Select * From DEMO
Start With ID = '00113' --以id=00113作为树的根开始递归
Connect By  Prior PID = ID --上一条的pid作为这一条的id(因为已知条件为id='00113',所以寻找本条记录的pid向上递归)

--结果
00113   延安  00011
00011   陕西  00001
00001   中国  -1

反映在如图所示的树上就为:从延安开始查询,查询到延安的父节点,然后以延安的父节点为根,查询延安的父节点(也就是陕西)的父节点,以此递归向上查询。

自上向下的递归

--自上向下
Select * From DEMO
Start With ID = '00001' -- 以id='00001'作为根递归查询
Connect By  Prior ID = PID -- 上一条记录的id作为本条记录的pid来查询,因为已知条件为id='00001',故以id='00001'为根,向下递归查询

--结果
00001   中国  -1
00011   陕西  00001
00111   西安  00011
00112   咸阳  00011
00113   延安  00011
00012   贵州  00001
00013   河南  00001

结合上图所示的树:从中国开始查询,访问根节点,再遍历左子树,即树的先序遍历。

加where子句的递归查询

Select ID, PID, DSC
From DEMO
WHERE ID <> '00011'  -- 不能在最后部分加where,不能在connect by最后面再加.
Start With ID = '00001'
Connect By Prior ID =  PID

--结果
00001   -1      中国
00111   00011   西安
00112   00011   咸阳
00113   00011   延安
00012   00001   贵州
00013   00001   河南

可以看成与递归查询无关.只是对整个结果起过滤作用。

nocycle关键字、level关键字、connect_by_isleaf isLeaf

在Oracle中的role是禁止出现循环的.比如你grant A to B ,grant B to C .再来个grant C to A会出错的。如果树中有环的话在递归查询中会报错,可以用nocycle关键字来消除环。

如:假设上述的表中 ID ‘00001‘ 记录的 ‘PID‘ 也改为 ‘00001‘, 会出现循环的问题, 这时,需要用到 nocycle 即可消除循环。

Select ID, PID, DSC,
connect_by_isleaf isLeaf, -- 表示当前节点是否是叶子节点
LEVEL -- 表示当前节点所处层级, 这里的层级指的是 从 start with 查询到的节点开始往下算起, 当前属于第几层级
From DEMO
Connect By nocycle Prior ID = PID -- 在这里加入nocycle
Start With ID = '00001';

-- 结果
Select ID, PID, DSC,
connect_by_isleaf isLeaf,
LEVEL
From DEMO
Connect By nocycle Prior ID = PID
Start With ID = '00001';

--结果
ID      PID     DSC  isLeaf     LEVEL
00001   00001   中国  0           0
00011   00001   陕西  0           1
00111   00011   西安  1           2
00112   00011   咸阳  1           2
00113   00011   延安  1           2
00012   00001   贵州  1           1
00013   00001   河南  1           1

这里需要注意的一个点, 如果采用的是 自底向上的 方式查询, 则 LEVEL 的 层级 同样是 从底向上, 如 00113 LEVEL 1 00011 LEVEL 2 00001 LEVEL 3。

另外一点: 如果在查询语句中 Select ID, PID, DSC, connect_by_isleaf isLeaf, LEVEL - 1 LEVEL 这种查询方式的话, 在 WHERE 判断条件中, 只需要判断 LEVEL = 1, 就可以取出 当前查询节点的子节点(由于LEVEL 也是 伪列, 需要用子查询的方式);

SIBLINGS关键字、connect_by_iscycle

它会保护层次,并且在每个等级中按expre排序。

Select ID, PID, DSC,
connect_by_isleaf, -- 存在循环,将返回1,否则返回0
LEVEL
From DEMO
Start With ID = '00001'
Connect By nocycle Prior ID =  PID
ORDER By DSC
--结果, 仅贴出部分数据(层级结构被破坏了)
00012   00001   贵州  1   2
00013   00001   河南  1   2
00011   00001   陕西  0   2
00111   00011   西安  1   3
00112   00011   咸阳  1   3
00113   00011   延安  1   3
00001   -1      中国  0   1
--ORDER SIBLINGS  By DSC
Select ID, PID, DSC,
connect_by_isleaf, -- 存在循环,将返回1,否则返回0
LEVEL
From DEMO
Start With ID = '00001'
Connect By nocycle Prior ID =  PID
ORDER SIBLINGS  By DSC
--结果(Level 层级不变)
00001   -1      中国  0   1
00012   00001   贵州  1   2
00013   00001   河南  1   2
00011   00001   陕西  0   2
00111   00011   西安  1   3
00112   00011   咸阳  1   3
00113   00011   延安  1   3

start with ... connect by 递归查询

标签:role   五步   evel   key   语法   取出   rom   expr   分数   

原文地址:https://www.cnblogs.com/codebetter/p/10480822.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!