您的位置:首页 > 数据库 > Oracle

oracle:两条sql语句实现层次查询的反序权值计算与输出

2007-05-27 18:27 861 查看
这张存放商品及零件信息(事实上行业里有专门的名字,这里由于种种原因暂且使用这样一种不太确切的名字)的表内有三个主要的字段:父节点代码,子节点代码,权重。父节点与子节点用来描述商品或所含零件之间的上下级包含关系,最终的成品代码一定是最上层的根节点。而权重描述了每个子节点(零件)与其父节点之间的数量对应关系。比如,一台完整的电脑就是最终的商品,它由显示器,主机,鼠标,键盘构成,而主机又由主板,cpu,硬盘,内存,光驱等零件构成,主板又分为......可以用一幅图直观反映出来



图1 商品与零件构成树

那么,一台计算机对应一个主机或者说他们的构成比例是1:1,这也就是主机子节点的权重。而一台主机如果包含两块硬盘的话,则硬盘的权重就是1:2。如果两台计算机公用一台显示器,则显示器的权重就是2:1。对于这样的表结构,客户的要求就是按照从上到下从右到左的顺序输出每个节点以及其权重,需要注意的是此时的权重并不单纯是该子节点本身在表中存储的权重值,而是以根节点个数1为基准,向子节点依次累计的权重值,这里称为累计因数。比如如果一块硬盘有四张盘片,则对于一台电脑而言包含1*2*4=8张盘片,盘片的累计因数是8。

此时,要想输出树状层次的数据我们会首选connect by...start with...语句,如下:

SELECT
level,
pare_item_cod,
chil_item_cod
FROM
m_structure
WHERE
del_F=0 start with del_F=0 AND
pare_item_Cod='MN2_TEST1-1' connect by prior chil_item_cod=pare_item_cod

其中'MN2_TEST1-1' 是根节点代码也是父节点代码,这条语句执行时将从该节点往下从左边子节点一直找到最左边叶子结点然后再找其父节点的右子节点,对整棵树进行深度优先搜索。这一过程是递归进行的。但是,它并不满足我们对顺序的要求。同时,每个节点的累计因数也算不出来,因为我们无法控制递归的过程,以在此过程中计算累计因数。如图2所示:



图2 普通层次查询语句的输出结果

为了解决遍历顺序的问题,我们首先会想到增加order by字句,即先按照父节点pare_item_cod按升序排列,然后对子结点chil_item_cod按降序排列,那么递归的过程就是从上到下,从右到左。查询语句如下:

SELECT
level,
pare_item_cod,
chil_item_cod
FROM
m_structure
WHERE
del_F=0 start with del_F=0 AND
pare_item_Cod='MN2_TEST1-1' connect by prior chil_item_cod=pare_item_cod
ORDER BY
pare_item_cod asc,
chil_item_cod desc

执行结果怎样呢,如下图3所示,事情并没有想象中那么简单。



图3 使用order by子句的递归顺序

显然,单单使用order by 子句会破坏递归结果的层次关系,使整个sql语句丧失了原有的意义。order siblings by关键字恰恰能解决这样的问题,它既能维持递归时的层次关系,又能使得同层节点按照规定的顺序输出。执行结果如图4所示。



图4 使用order siblings by使得遍历结果按照规定的顺序输出

至此,节点输出顺序的问题已经得到解决,下面来看如何计算各层节点的累计因子。尽管start with ...connect by这样的递归查询是一次性完成的,我们不能控制其执行的过程,从而在遍历的每个阶段将各节点的累积因子统计出来,但是我们会发现一个规律,就是各节点的累积因子就是从该结点按照递归顺序的逆序回到根节点所碰到的所有节点累积因子的乘积。这样一来,只要我们能够知道一个节点到最上层根节点的搜索过程中都有哪些节点,问题就有希望得到解决。这时,我们还是要利用oracle层次查询语句中的一个特征:遍历路径SYS_CONNECT_BY_PATH(chil_item_cod,‘/’) AS PATH,它会将一个节点到根节点间的所有搜索到的节点输出成一个字符串,中间用“/”分隔。接下来我们需要模仿上面的sql语句再写一条sql语句,不同的是这条层次便利的sql语句是从某一子节点开始一直遍历到根节点的,如下:

SELECT
level,
chil_item_cod,
SYS_CONNECT_BY_PATH(chil_item_cod,‘/’) AS PATH
FROM
m_structure
WHERE
del_F=0 start with del_F=0 AND
pare_item_Cod='MN2_TESTXX' connect by prior pare_item_cod=chil_item_cod

其中,start with条件中的pare_item_cod节点名来自于上面一条sql语句输出节点中的一个。比如上面一条sql语句输出树最右边的“4-2”节点,那么这里pare_item_Cod='MN2_TEST4-2'。输出的PATH数据域的值就是 “2-1/3-2/3-1/4-2”,当然最上面的根我们是知道的“1-1” 。这样就得到了从根节点到指定子节点的所有遍历节点序列,下面的事情就是在程序中使用一个循环将这里各个节点的权值从上到下乘起来,就能够得到指定的那个子节点的累计因子。

总结一下,通过图4中递归查询语句与上面这条递归查询语句相结合,我们不但可以对层次型的数据按照指定的顺序进行输出,还可以完成各个节点上的累计因子的计算。其间,我们不但使用了oracle的基本层次查询关键字start with...connect by,还综合使用了order siblings by关键字以及遍历路径输出关键字sys_connect_by_path(),再配合具体的程序逻辑,实现比较复杂的功能。当然,这篇文章论述的原理和特性大多基于oracle,如果使用sql server或者db2数据库则需要另辟蹊径。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐