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

oracle 10g 树形查询

2011-03-13 10:15 239 查看
在开发中遇到过树形查询,一直弄不太清楚,今天把oracle 10g的树形查询进行一下总结,并把新特性展现给大家,很多东西来源于网上,只是自己总结整理了一下。

1.基本语法

connect by 是结构化查询中用到的,其基本语法是:
select ... from tablename

where cond3

start by cond1
connect by cond2 ;
简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段:
id,parentid那么通过表示每一条记录的parent是谁,就可以形成一个树状结构。
用上述语法的查询可以取得这棵树的所有记录。
其中COND1是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。
COND2是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR ID=PRAENTID就是说上一条记录的ID是本条记录的PRAENTID,即本记录的父亲是上一条记录。
COND3是过滤条件,用于对返回的所有记录进行过滤。

PRIOR和START WITH关键字是可选项
PRIORY运算符必须放置在连接关系的两列中某一个的前面。对于节点间的父子关系,PRIOR
运算符在一侧表示父节点,在另一侧表示子节点,从而确定查找树结构是的顺序是自顶向下还是
自底向上。在连接关系中,除了可以使用列名外,还允许使用列表达式。START WITH 子句为
可选项,用来标识哪个节点作为查找树型结构的根节点。若该子句被省略,则表示所有满足查询
条件的行作为根节点。
注意:网上部份把where cond3 写在最后是不对,不符合语法,会报错。下面是结合生产库中的一些实际表进行测试
a.表结构

create table tr_merge_item
(
merge_item_type_id number(12) not null,
name varchar2(400) not null,
type_code number(15),
sum_item_type_id number(12),
merge_group_id number(6) not null,
state_date date,
state varchar2(6) not null
)
;
b.例子语句增加了oracle 10g的几个特性
select * from (
select
merge_item_type_id,
name,
type_code,
sum_item_type_id,
merge_group_id,
state_date,
state,
connect_by_isleaf leaf, -- 判断是否为叶结点
sys_connect_by_path(name,'|') path,-- 遍历的路径
connect_by_root(name) root, -- 遍历根结点
-- connect_by_iscycle -- 查询树是否有环路
level -- 结点所属树的层数
from sys.tr_merge_item t
where t.merge_group_id = 129
start with t.sum_item_type_id is null
connect by prior t.merge_item_type_id = t.sum_item_type_id

)
where leaf = 1
;
commit;
二.下面逐一介结这些特性,当然也包括以前版本
a.connect_by_isleaf -- 这个是oracle 10g 新增的特性 判断结点是否为叶结点,这个特性很实用,当然我拿来一个树时,往往是只需要找到叶结点后,再与事实表进行关联,下面以一下网上的小例子展示给大家:
1.这个树形结构是网上比较典型的,非常直观的看到结果以便进行验证。
A
/ /
B C
/ /
D E
/ /
F G
2.创建表(t),并insert 数据,其他特性均以这个表的实例进行演示

create table t
(
x varchar2(30),
y varchar2(30),
z varchar2(30)
)
;

insert into t values ('A','1',null);
insert into t values ('B','2','1');
insert into t values ('C','3','1');
insert into t values ('D','4','2');
insert into t values ('E','5','3');
insert into t values ('F','6','4');
insert into t values ('G','7','4');
commit;
3.connect_by_isleaf -- 这个是oracle 10g 新增的特性 判断结点是否为叶结点,这个特性很实用,当然我拿来一个树时,往往是只需要找到叶结点后,再与事实表进行关联,下面以一下网上的小例子展示给大家:验证语句如下

select t.x,t.y,t.z,connect_by_isleaf from t t
start with z is null -- 从A结点开始遍历
connect by prior y = z -- 上一行的y与下一行的Z(不要看的太死,这个”一“指的是遍历的意思
;
commit;



4.connect_by_root -- 这个一元运算符只能在层次查询中使用,功能很简单,可以得到每个分支的根节点信息,注意这个一元运算符,说白了就是要有一个输入参数。验证语句如下:
select t.x,t.y,t.z,connect_by_isleaf,connect_by_root(x) from t t
start with z is null
connect by prior y = z
;
commit;



以上很清楚,所有有结点的根结点都是A结点。
5.connect_by_iscycle 这个是一个伪列,主要目的就是验证这个树是否有环,我们经常在配置树时,稍有不小心就会造成这个现象,但又不知道是那个结点出了问题,这个功能正好解决了这一问题,所以说这个特性实用性我觉得还是高的。
首先我就在源数据的基础上造一个环路。
update t
set t.z=4
where t.x= 'A'
;
commit;



当我们执行验证connect_by_root语句就会报错,提示出现循环:



当出现这种问题,我们的任务就是把这样的记录找出来,这时connect_by_iscycle的功能就突现出来了。
对于这个问题我觉,首先找到是那个结点出的问题,然后向上或者向个遍历找到出现的那个结点把相应的值改一下问题就解决了。
以下是自己想的解决问题方法。
a.找到问题结点
select t.x,t.y,t.z,connect_by_iscycle from t t
start with x='A'
connect by nocycle prior y = z
;
commit;



b.向上遍边找到问题结点
select t.x,t.y,t.z,connect_by_iscycle from t t
start with x='D'
connect by nocycle prior z = y
;
commit;



说明一下,由于我这个例子比较特珠,开始结点就有问题,导致不是很明显,但解决问题的方法是一样的。
6.level 是一个伪列,用于返回结点所在的层数,这里结合叶结点(connect_by_isleaf)进行一个生产环境的实际应用。
我们先找到叶结点,然后找到最大层数,进行自关联生成具有层次结构的维表,这个在实际应用中特别重要。
a.
select max(level_cnt) from (
select
merge_item_type_id,
name,
type_code,
sum_item_type_id,
merge_group_id,
state_date,
state,
connect_by_isleaf leaf,
sys_connect_by_path(name,'|') path,
connect_by_root(name) root,
level level_cnt
-- connect_by_iscycle
from sys.tr_merge_item t
where t.merge_group_id = 129
start with t.sum_item_type_id is null
connect by prior t.merge_item_type_id = t.sum_item_type_id

)
where leaf = 1
;
commit;



b.
进行自关联得到层次维表
create table sys.std_complaint_all_type as
select
t5.type_code std_complaint_type_id,
t5.name std_complaint_type_name,
t4.type_code std_complaint_type_id4,
t4.name std_complaint_type_name4,
t3.type_code std_complaint_type_id3,
t3.name std_complaint_type_name3,
t2.type_code std_complaint_type_id2,
t2.name std_complaint_type_name2,
t1.type_code std_complaint_type_id1,
t1.name std_complaint_type_name1
from
sys.tr_merge_item t1 ,
sys.tr_merge_item t2 ,
sys.tr_merge_item t3 ,
sys.tr_merge_item t4 ,
sys.tr_merge_item t5
where t1.merge_item_type_id = t2.sum_item_type_id
and t2.merge_item_type_id = t3.sum_item_type_id
and t3.merge_item_type_id = t4.sum_item_type_id
and t4.merge_item_type_id = t5.sum_item_type_id
and t5.merge_group_id = 129 and t1.state='00A'
;
7. sys_connect_by_path -- 实现将从父节点到当前行内容以“path”或者层次元素列表的形式显示出来
select t.x,t.y,t.z,connect_by_iscycle,sys_connect_by_path(x,'|') from t t
start with x='A'
connect by nocycle prior y = z
;
commit;

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: