现在,举一个比较复杂的例子(例子七)。要求将图一所描述的层次数据变成横向表格,所有的叶结点必须在第一格,后续的格原则上是该叶结点在不同层次数据上的父节点或祖先节点的节点编号,但如果叶结点的层次比较高,在低于其层次上的层次结点的编号延用其自身的编号不变,如下表七:
叶结点编号 |
位于层次4上的父节点 |
位于层次3上的父节点 |
位于层次2上的父节点 |
位于层次1上的父节点 |
r |
k |
e |
b |
a |
s |
k |
e |
b |
a |
t |
k |
e |
b |
a |
u |
l |
e |
b |
a |
v |
m |
e |
b |
a |
w |
n |
e |
b |
a |
x |
o |
j |
d |
a |
y |
p |
j |
d |
a |
z |
q |
j |
d |
a |
f |
f |
f |
b |
a |
g |
g |
g |
c |
a |
h |
h |
h |
d |
a |
i |
i |
i |
d |
a |
表七
读者不妨自己试试看,编写一个SQL语句来完成输出的结果如表七中的记录,次序无关。如果不用我们提到的层次数据的概念,想通过一个SQL语句完成上述的任务,几乎是不可能的。我们在这里应用层次数据的概念就可以通过一个SQL语句来完成上述的功能,达到需要的结果。代码如下,不妨一试:
select a.node,b.node,c.node,d.node,e.node from (select node ,parent_node from hierarchical_data_test where level=5 start with node='a' connect by prior node=parent_node ) a, (select node ,parent_node from hierarchical_data_test where level=4 start with node='a' connect by prior node=parent_node ) b, (select node ,parent_node from hierarchical_data_test where level=3 start with node='a' connect by prior node=parent_node ) c, (select node ,parent_node from hierarchical_data_test where level=2 start with node='a' connect by prior node=parent_node ) d, (select node ,parent_node from hierarchical_data_test where level=1 start with node='a' connect by prior node=parent_node ) e where a.parent_node=b.node and b.parent_node=c.node and c.parent_node=d.node and d.parent_node=e.node union select b.node,b.node,c.node,d.node,e.node from (select node ,parent_node from hierarchical_data_test where level=4 and node not in (select parent_node from hierarchical_data_test where parent_node is not null) start with node='a' connect by prior node=parent_node ) b, (select node ,parent_node from hierarchical_data_test where level=3 start with node='a' connect by prior node=parent_node ) c, (select node ,parent_node from hierarchical_data_test where level=2 start with node='a' connect by prior node=parent_node ) d, (select node ,parent_node from hierarchical_data_test where level=1 start with node='a' connect by prior node=parent_node ) e where b.parent_node=c.node and c.parent_node=d.node and d.parent_node=e.node union select c.node,c.node,c.node,d.node,e.node from (select node ,parent_node from hierarchical_data_test where level=3 and node not in (select parent_node from hierarchical_data_test where parent_node is not null) start with node='a' connect by prior node=parent_node ) c, (select node ,parent_node from hierarchical_data_test where level=2 start with node='a' connect by prior node=parent_node ) d, (select node ,parent_node from hierarchical_data_test where level=1 start with node='a' connect by prior node=parent_node ) e where c.parent_node=d.node and d.parent_node=e.node union select d.node,d.node,d.node,d.node,e.node from (select node ,parent_node from hierarchical_data_test where level=2 and node not in (select parent_node from hierarchical_data_test where parent_node is not null) start with node='a' connect by prior node=parent_node ) d, (select node ,parent_node from hierarchical_data_test where level=1 start with node='a' connect by prior node=parent_node ) e where d.parent_node=e.node
在这里有一点要提醒读者注意,上述语句中node not in (select parent_node from hierarchical_data_test where parent_node is not null)部分中的代码where parent_node is not null没有的话,返回的节点只有第五层叶结点的记录,二、三、四层上的叶结点都无法选出,这是为什么呢?原因就出在我们定义图一所示的数据时,根节点a的父节点字段中的值被我们设置成为空(null),所以语句select parent_node from hierarchical_data_test 返回的数据中包含null。象这样包含null的返回数据作为子查询的结果做not in操作时,将不会有结果返回,这点在Oracle中遇到同样的问题时都是如此,因此要特别注意。从而可知,在整个层次数据根节点的父节点标示字段中,我们可以采用一个不常用编码值表示,以区别结点编码(如-1);或者,在涉及到整个层次数据根节点时,我们在代码中要注意where parent_node is not null条件的适时加入。
现实工作中层次查询的使用和意义
在我们日常工作中,涉及到的层次数据的方方面面很多。如人事管理方面,我们可以从某一节点上溯到最高层的领导,也可以下溯到他的任意级下属;地理信息和行政范围管理方面,也可以充分利用层次查询来获取想要的结果;财务管理方面,我们可以将某一费用归结到某一个大类上面,也可以从某一大类出发查找有哪些子类的账目组成。
四、结束语
总之,在掌握Oracle中层次查询这个工具后,如何充分有效地利用以方便我们的日常工作,则依靠读者的理解与智慧了。
参考文献
1.ORACLE,ORACLE8TM SERVER SQL REFERENCE Release 8.0,June,1997
|