oracle ---递归查询(start with --connect by prior )

递归查询要处理的问题:树形结构数据,存储在一张表中,然后通过start with --connect by prior-来进行遍历

示例基础:

create table a_test

( p_id  varchar2(10),

   id    varchar2(10));

insert into a_test values ( '', '1' );
insert into a_test values ( '1', '2' );
insert into a_test values ( '1', '3' );
insert into a_test values ( '2', '4' );
insert into a_test values ( '2', '5' );
insert into a_test values ( '3', '6' );
insert into a_test values ( '3', '7' );
insert into a_test values ( '5', '8' );
insert into a_test values ( '5', '9' );
insert into a_test values ( '7', '10' );
insert into a_test values ( '7', '11' );
insert into a_test values ( '10', '12' );
insert into a_test values ( '10', '13' );
SELECT * FROM a_test

oracle ---递归查询(start with --connect by prior )

数据结构图

oracle ---递归查询(start with --connect by prior )

给出一个节点根据节点查询,节点一下的数据如

例1:SELECT  ID ,P_ID ,LEVEL FROM a_test  START WITH P_ID = 3 CONNECT BY PRIOR ID  = P_ID

oracle ---递归查询(start with --connect by prior )

根据返回的结果集可以看出,通过这个语句,我们得到了3节点以下的所有值(没有包含3这条数据

所以,START WITH 后跟的条件为查询的树形结构的起始节点;

 CONNECT BY  后跟的就是遍历的条件;

关键字 PRIOR 就定义了遍历的方向,若是PRIOR与父级字段一起则向上查询,与子级字段则向下查询 

向上查询:例2:SELECT  ID ,P_ID ,LEVEL FROM a_test  START WITH P_ID = 3 CONNECT BY ID  = PRIOR P_ID

oracle ---递归查询(start with --connect by prior )

向下查询:见例1;

where子句放在strat with之前,否则会报错

SELECT  ID ,P_ID ,LEVEL FROM a_test where LEVEL in (1,2) START WITH ID = 3 CONNECT BY PRIOR ID  =  P_ID

oracle ---递归查询(start with --connect by prior )

start with 嵌套使用,若是有这样需求时,给出一个子节点的值,要求查出该子节点父节点之下的所有值,

此时我想到的就是使用两次递归查询一次查询出当前子节点的父节点,然后以父节点为跟查询父节点下的所有值

嵌套使用

select ID ,P_ID,LEVEL 
FROM  a_test 
START WITH ID IN (SELECT  ID 
                 FROM a_test 
                 where LEVEL = 2 
                 START WITH ID = 7 
                 CONNECT BY  ID  =  PRIOR P_ID )
CONNECT BY PRIOR ID  =   P_ID  

 这样虽然能实现需求,但是这样查询的效率很低,怀疑是在递归查询的过程中子查询会反复执行

用with语句来解决

WITH temp  as (SELECT  ID 
                 FROM a_test 
                 where LEVEL = 2 
                 START WITH ID = 7 
                 CONNECT BY  ID  =  PRIOR P_ID)
select ID ,P_ID,LEVEL 
FROM  a_test 
START WITH ID IN (select * from  temp)
CONNECT BY PRIOR ID  =   P_ID

这样先吧子查询查出来,然后再进行另一个递归查询

(ps:数据量稍微多就会产生明显的差距,具体原因么有查询出来,之前的判断仅为猜测!)