oracle 里有关树查询

格式:
SELECT column
FROM  table_name
START WITH  column=value
CONNECT  BY  PRIOR  父主键=子外键

 select lpad('   ',4*(level-1))||name name,job,id,super from emp
 start with super is null
 connect by prior id=super

 

 

例子:
原始数据:select no,q from a_example2

NO          NAME
---------- ------------------------------
001         a01
001         a02
001         a03
001         a04
001         a05
002         b01
003         c01
003         c02
004         d01
005         e01
005         e02
005         e03
005         e04
005         e05

需要实现得到结果是:
001    a01;a02;a03
002    b01
003   c01;c02
004   d01
005   e01;e02;e03;e04;e05

思路:
1、ORACLE8.1之后有个connect by 子句,取出整棵树数据。
create table a_example1
(
no char(3) not null,
name varchar2(10) not null,
parent char(3)
)

insert into a_example1
values('001','老王',null)

insert into a_example1
values('101','老李',null)

insert into a_example1
values('002','大王1','001')

insert into a_example1
values('102','大李1','101')

insert into a_example1
values('003','大王2','001')

insert into a_example1
values('103','大李2','101')

insert into a_example1
values('003','小王1','002')

insert into a_example1
values('103','小李1','102')

NO  NAME PARENT
001 老王
101 老李
002 大王1 001
102 大李1 101
003 大王2 001
103 大李2 101
003 小王1 002
103 小李1 102


//按照家族树取数据
select * from a_example1

select level,sys_connect_by_path(name,'/') path
             from a_example1
             start with /*name = '老王' and*/ parent is null
             connect by parent = prior no
结果:
1   /老王
2   /老王/大王1
3   /老王/大王1/小王1
2   /老王/大王2
1   /老李
2   /老李/大李1
3   /老李/大李1/小李1
2   /老李/大李2

按照上面思路,我们只要将原始数据做成如下结构:
NO         NAME
001         a01
001        a01/a02
001        a01/a02/a03
001        a01/a02/a03/a04
001        a01/a02/a03/a04/a05
002         b01
003        c01
003         c01/c02
004         d01
005         e01
005         e01/e02
005         e01/e02/e03
005         e01/e02/e03/e04
005         e01/e02/e03/e04/e05

最后按NO分组,取最大的一个值即为所需的结果。
NO         NAME
001        a01/a02/a03/a04/a05
002         b01
003         c01/c02
004         d01
005         e01/e02/e03/e04/e05

SQL语句:
select no,max(sys_connect_by_path(name,';')) result from
                (select no,name,rn,lead(rn) over(partition by no order by rn) rn1
                from (select no,name,row_number() over(order by no,name desc) rn from a_example2)
                )
         start with rn1 is null connect by rn1 = prior rn
group by no


语句分析:
1、 select no,name,row_number() over(order by no,name desc) rn from a_example2
按照NO升序排序,同时按照NAME降序排序,产生伪列,目的是要形成树结构
NO  NAME RN
001       a03      1
001       a02      2
001       a01      3
002       b01      4
003       c02      5
003       c01      6
004       d01      7
005       e05      8
005       e04      9
005       e03      10
005       e02      11
005       e01      12

2、select no,name,rn,lead(rn) over(partition by no order by rn) rn1
from ( select no,name,row_number() over(order by no,name desc) rn from a_example2)
生成家族谱,即子节点与父节点有对应关系,对应关系通过rn和 rn1。其中lead为上一条记录的RN值

NO  NAME RN  RN1                                                        001        a03     1        2   --说明:针对NO=001来说,其下一条记录的RN=2     001        a02     2        3 --说明:针对NO=001来说,其下一条记录的RN=3      001        a01     3         --说明:针对NO=001来说,其下一条记录的RN IS NULL 
002        b01     4                                                                      003        c02     5        6                                                             003        c01     6                                                                      004        d01     7                                                                      005        e05     8        9                                                             005        e04     9        10                                                            005        e03     10       11                                                            005        e02     11       12                                                            005        e01     12  

3、select no,sys_connect_by_path(name,';') result from
        (select no,name,rn,lead(rn) over(partition by no order by rn) rn1
from ( select no,name,row_number() over(order by no,name desc) rn from a_example2))
        start with rn1 is null connect by rn1 = prior rn
正式生成树  
NO   RESULT
001       ;a01
001       ;a01;a02
001       ;a01;a02;a03
002       ;b01
005       ;e01
005       ;e01;e02
005       ;e01;e02;e03
005       ;e01;e02;e03;e04
005       ;e01;e02;e03;e04;e05
003       ;c01
003       ;c01;c02
004       ;d01

将上面结果按照NO分组,取result最大值即可,所以将上述语句改为
select no,max(sys_connect_by_path(name,';')) result from
                (select no,name,rn,lead(rn) over(partition by no order by rn) rn1
                from (select no,name,row_number() over(order by no,name desc) rn from a_example2)
                )
         start with rn1 is null connect by rn1 = prior rn
group by no
得到所需结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值