6 |
s |
k |
7 |
t |
k |
8 |
l |
e |
9 |
u |
l |
10 |
m |
e |
11 |
v |
m |
12 |
n |
e |
13 |
w |
n |
14 |
f |
b |
15 |
c |
a |
16 |
g |
c |
17 |
d |
a |
18 |
h |
d |
19 |
i |
d |
20 |
j |
d |
21 |
o |
j |
22 |
x |
o |
23 |
p |
j |
24 |
y |
p |
25 |
q |
j |
26 |
z |
q |
表二
通过比较表一和表二,我们可以清晰地看到,步骤五中提到的层次数据的显示次序,请读者自己在例子一语句上再加上ORDER BY NODE ,看一下效果,理解SELECT语句执行层次查询时将遵循的限制中的第二点。
例子二:选择出图一中节点d的所有子孙节点的记录
select * from hierarchical_data_test start with node='d' connect by parent_node=prior node
显示次序 |
节点 |
父节点 |
1 |
d |
a |
2 |
h |
d |
3 |
i |
d |
4 |
j |
d |
5 |
o |
j |
6 |
x |
o |
7 |
p |
j |
8 |
y |
p |
9 |
q |
j |
10 |
z |
q |
表三
我们通过例子二可以看到,prior位置在等号左或者右并不重要,关键它在哪个字段的前面进行描述。
例子三:选择出图一中节点d的所有子孙节点的记录,同时要求节点编号在l与y之间
select * from cal. hierarchical_data_test where node between 'l' and 'y' start with node='d' connect by prior node=parent_node
显示次序 |
节点 |
父节点 |
1 |
o |
j |
2 |
x |
o |
3 |
p |
j |
4 |
y |
p |
5 |
q |
j |
表四
如果我们将语句变成为如下:
select * from hierarchical_data_test start with node='d' connect by prior node=parent_node and node between 'l' and 'y'
表五
请读者自行比较表四与表五两者之间的不同,领会Oracle在层次查询时的工作步骤和对结果集的选择。
LEVEL伪列在层次查询中的使用
伪列不是表中真正的列,只是从语法上讲,它们的处理方式和表中的列是很类似的。当像真正的表中的列一样被引用时,这些伪列将会返回值。伪列主要用于给程序员提供更多的工具,以便在代码中使用。
SELECT层次查询中,可以使用LEVEL伪列来显示层次数据间的层次。LEVEL对于选定的根节点返回值为1,对于该根节点的子节点返回为2,孙子辈节点返回3,依次类推。LEVEL在层次查询中返回的结果将会受到用户可用内存的影响。
例子四:
select lpad(' ',2*(level-1))||node
from hierarchical_data_test
start with node='a' connect by prior node=parent_node
该语句的返回结果为:
a
b
e
k
r
s
t
l
u
m
v
n
w
f
c
g
d
h
i
j
o
x
p
y
q
z
从上例结果结合图一,我们可以清晰地看到,整个层次数据之间的层次关系被这种缩进格式明显地体现出来。关于lpad()函数的使用,请读者参考有关的书籍。
假设我们只想看到层次数据的前三层,可以用如下的语句:
select lpad(' ',2*(level-1))||node from hierarchical_data_test start with node='a' connect by prior node=parent_node and level <=3
层次查询的探讨
细心的读者可能注意到CONNECT BY 从句中的PRIOR的位置,现在我们将其位置移到parent_node前,如例子五:
select * from hierarchical_data_test start with node='u' connect by prior parent_node= node
返回的结果为:
显示次序 |
节点 |
父节点 |
1 |
u |
l |
2 |
l |
e |
3 |
e |
b |
4 |
b |
a |
5 |
a |
|
表六
我们发现,如果我们将PRIOR放在parent_node前,返回的结果是从节点u上溯到根节点a,这正是一个从子孙节点寻找祖先节点的过程。当然,这儿也可以使用伪列LEVEL,查找到上几级祖先,例如节点u查找上三代祖先,可以在connect by prior parent_node= node后再加上and level<=4。这里为什么是4而不是3?因为根节点本身算层数1,三代祖先就要在1的基础上再加上3。
例子六:找出节点u三代祖先繁衍的所有的亲戚节点的记录
select distinct * from hierarchical_data_test start with node in ( select node from hierarchical_data_test start with node='u' connect by prior parent_node= node and level <=4) connect by prior node=parent_node
这里为什么会用distinct?读者不妨去掉distinct一试,看一下两者之间的差别。
|