oracle--15树形查询

Oracle查询树形结构
oracle中的select语句可以用START WITH...CONNECT BY PRIOR子句实现递归查询,connect by 是结构化查询中用到的,其基本语法是:
select * from tablename start with cond1
connect by cond2
where cond3;
简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段:
id,parentid那么通过表示每一条记录的parent是谁,就可以形成一个树状结构。
用上述语法的查询可以取得这棵树的所有记录。
其中COND1是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。
COND2是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR ID=PRAENTID就是说上一条记录的ID是本条记录的PRAENTID,即本记录的父亲是上一条记录。
COND3是过滤条件,用于对返回的所有记录进行过滤。
对于oracle进行简单树查询(递归查询)
DEPTID           NUMBER                   部门id
PAREDEPTID   NUMBER                   父部门id(所属部门id)
NAME              CHAR (40 Byte)        部门名称
通过子节点向根节点追朔.
select * from persons.dept start with deptid=76 connect by prior paredeptid=deptid
通过根节点遍历子节点.
select * from persons.dept start with paredeptid=0 connect by prior deptid=paredeptid
可通过level 关键字查询所在层次.
select a.*,level from persons.dept a start with paredeptid=0 connect by prior deptid=paredeptid
PS:start with 后面所跟的就是就是递归的种子,也就是递归开始的地方;
connect by  prior后面的字段顺序是有讲究的;
若prior缺省:则只能查询到符合条件的起始行,并不进行递归查询;
 例:
select * from table
start with org_id = 'HBHqfWGWPy'
connect by prior org_id = parent_id;
简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段:
org_id,parent_id那么通过表示每一条记录的parent是谁,就可以形成一个树状结构。
用上述语法的查询可以取得这棵树的所有记录。
其中:
条件1 是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。
条件2 是连接条件,其中用PRIOR表示上一条记录,
比如 CONNECT BY PRIOR org_id = parent_id就是说上一条记录的org_id 是本条记录的parent_id,即本记录的父亲是上一条记录。
条件3 是过滤条件,用于对返回的所有记录进行过滤。
简单介绍如下:
在扫描树结构表时,需要依此访问树结构的每个节点,一个节点只能访问一次,其访问的步骤如下:
第一步:从根节点开始;
第二步:访问该节点;
第三步:判断该节点有无未被访问的子节点,若有,则转向它最左侧的未被访问的子节点,并执行第二步,否则执行第四步;
第四步:若该节点为根节点,则访问完毕,否则执行第五步;
第五步:返回到该节点的父节点,并执行第三步骤。
总之:扫描整个树结构的过程也即是中序遍历树的过程。
1. 树结构的描述
树结构的数据存放在表中,数据之间的层次关系即父子关系,通过表中的列与列间的关系来描述, 如 EMP 表中的 EMPNO 和 MGR 。 EMPNO 表示该雇员的编号, MGR 表示领导该雇员的人的编号,即子节点的 MGR 值等于父节点的 EMPNO 值。在表的每一行中都有一个表示父节点的 MGR (除根节点外),通过每个节点的父节点,就可以确定整个树结构。
在 SELECT 命令中使用 CONNECT BY 和 START WITH 子句可以查询表中的树型结构关系。其命令格式如下:
SELECT 。。。
CONNECT BY {PRIOR 列名 1= 列名 2| 列名 1=PRIOR 裂名 2}
[START WITH] ;
其中: CONNECT BY 子句说明每行数据将是按层次顺序检索,并规定将表中的数据连入树型结构的关系中。 PRIORY 运算符必须放置在连接关系的两列中某一个的前面。对于节点间的父子关系, PRIOR 运算符在一侧表示父节点,在另一侧表示子节点,从而确定查找树结构是的顺序是自顶向下还是自底向上。在连接关系中,除了可以使用列名外,还允许使用列表达 式。 START WITH 子句为可选项,用来标识哪个节点作为查找树型结构的根节点。若该子句被省略,则表示所有满足查询条件的行作为根节点。
START WITH: 不但可以指定一个根节点,还可以指定多个根节点。
2. 关于 PRIOR
运算符 PRIOR 被放置于等号前后的位置,决定着查询时的检索顺序。
PRIOR 被置于 CONNECT BY 子句中等号的前面时,则强制从根节点到叶节点的顺序检索,即由父节点向子节点方向通过树结构,我们称之为自顶向下 的方式。如:
CONNECT BY PRIOR EMPNO=MGR
PIROR 运算符被置于 CONNECT BY 子句中等号的后面时,则强制从叶节点到根节点的顺序检索,即由子节点向父节点方向通过树结构,我们称之为自底向上 的方式。例如:
CONNECT BY EMPNO=PRIOR MGR
在这种方式中也应指定一个开始的节点。
3. 定义查找起始节点
在自顶向下查询树结构时,不但可以从根节点开始,还可以定义任何节点为起始节点,以此开始向下查找。这样查找的结果就是以该节点为开始的结构树的一枝。
4.使用 LEVEL
在具有树结构的表中,每一行数据都是树结构中的一个节点,由于节点所处的层次位置不同,所以每行记录都可以有一个层号。层号根据节点与根节点的距离确定。不论从哪个节点开始,该起始根节点的层号始终为 1 ,根节点的子节点为 2 , 依此类推。
5.节点和分支的裁剪
在对树结构进行查询时,可以去掉表中的某些行,也可以剪掉树中的一个分支,使用 WHERE 子句来限定树型结构中的单个节点,以去掉树中的单个节点,但它却不影响其后代节点(自顶向下检索时)或前辈节点(自底向顶检索时)。
6.排序显示
象在其它查询中一样,在树结构查询中也可以使用 ORDER BY 子句,改变查询结果的显示顺序,而不必按照遍历树结构的顺序。


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

select ... from tablename start with 条件1

connect by 条件2

where 条件3;

例:

select * from table

start with org_id = 'HBHqfWGWPy'

connect by PRior org_id = parent_id;



简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段:

org_id,parent_id那么通过表示每一条记录的parent是谁,就可以形成一个树状结构。

用上述语法的查询可以取得这棵树的所有记录。

其中:

条件1 是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。

条件2 是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR org_id = parent_id就是说上一条记录的org_id 是本条记录的parent_id,即本记录的父亲是上一条记录。

条件3 是过滤条件,用于对返回的所有记录进行过滤。



简单介绍如下:

早扫描树结构表时,需要依此访问树结构的每个节点,一个节点只能访问一次,其访问的步骤如下:

第一步:从根节点开始;

第二步:访问该节点;

第三步:判断该节点有无未被访问的子节点,若有,则转向它最左侧的未被访问的子节,并执行第二步,否则执行第四步;

第四步:若该节点为根节点,则访问完毕,否则执行第五步;

第五步:返回到该节点的父节点,并执行第三步骤。

总之:扫描整个树结构的过程也即是中序遍历树的过程。



1. 树结构的描述

树结构的数据存放在表中,数据之间的层次关系即父子关系,通过表中的列与列间的关系来描述, 如EMP表中的EMPNO和MGR。EMPNO表示该雇员的编号,MGR表示领导该雇员的人的编号,即子节点的MGR值等于父节点的EMPNO值。在表的 每一行中都有一个表示父节点的MGR(除根节点外),通过每个节点的父节点,就可以确定整个树结构。

在SELECT命令中使用CONNECT BY 和蔼START WITH 子句可以查询表中的树型结构关系。其命令格式如下:

SELECT 。。。

CONNECT BY {PRIOR 列名1=列名2|列名1=PRIOR 裂名2}

[START WITH];

其中:CONNECT BY子句说明每行数据将是按层次顺序检索,并规定将表中的数据连入树型结构的关系中。PRIORY运算符必须放置在连接关系的两列中某一个的前面。对于节 点间的父子关系,PRIOR运算符在一侧表示父节点,在另一侧表示子节点,从而确定查找树结构是的顺序是自顶向下还是自底向上。在连接关系中,除了可以使 用列名外,还允许使用列表达式。START WITH 子句为可选项,用来标识哪个节点作为查找树型结构的根节点。若该子句被省略,则表示所有满足查询条件的行作为根节点。

START WITH: 不但可以指定一个根节点,还可以指定多个根节点。

2. 关于PRIOR

运算符PRIOR被放置于等号前后的位置,决定着查询时的检索顺序。

PRIOR被置于CONNECT BY子句中等号的前面时,则强制从根节点到叶节点的顺序检索,即由父节点向子节点方向通过树结构,我们称之为自顶向下的方式。如:

CONNECT BY PRIOR EMPNO=MGR

PIROR运算符被置于CONNECT BY 子句中等号的后面时,则强制从叶节点到根节点的顺序检索,即由子节点向父节点方向通过树结构,我们称之为自底向上的方式。例如:

CONNECT BY EMPNO=PRIOR MGR

在这种方式中也应指定一个开始的节点。

3. 定义查找起始节点

在自顶向下查询树结构时,不但可以从根节点开始,还可以定义任何节点为起始节点,以此开始向下查找。这样查找的结果就是以该节点为开始的结构树的一枝。

4.使用LEVEL

在具有树结构的表中,每一行数据都是树结构中的一个节点,由于节点所处的层次位置不同,所以每行记录都可以有一个层号。层号根据节点与根节点的距离确定。不论从哪个节点开始,该起始根节点的层号始终为1,根节点的子节点为2, 依此类推。图1.2就表示了树结构的层次。

5.节点和分支的裁剪

在对树结构进行查询时,可以去掉表中的某些行,也可以剪掉树中的一个分支,使用WHERE子句来限定树型结构中的单个节点,以去掉树中的单个节点,但它却不影响其后代节点(自顶向下检索时)或前辈节点(自底向顶检索时)。

6.排序显示

象在其它查询中一样,在树结构查询中也可以使用ORDER BY 子句,改变查询结果的显示顺序,而不必按照遍历树结构的顺序。



===================补充===================

Start with...Connect By子句递归查询一般用于一个表维护树形结构的应用。

创建示例表:

CREATE TABLE TBL_TEST

(

  ID    NUMBER,

  NAME  VARCHAR2(100 BYTE),

  PID   NUMBER                                  DEFAULT 0

);



插入测试数据:

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('1','10','0');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('2','11','1');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('3','20','0');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('4','12','1');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('5','121','2');



从Root往树末梢递归

select * from TBL_TEST

start with id=1

connect by prior id = pid



从末梢往树ROOT递归

select * from TBL_TEST

start with id=5

connect by prior pid = id

定义如下id 和 名称描述
1— 省长 <--- 2,3 (省长管辖市长、县长)
2— 市长 <--- 5,6 (市长管辖模范村村长和一个平民)
3— 县长 <--- 4,7,8,9 (县长管辖镇长和三个平民)
4— 镇长 <--- 10,11,12,13 (管辖四个平民)
5— 村长 <--- 14,15 (管辖两个平民)
其他(6-15)— 平民(没有管辖任何人)

只有省长、市长和县长能处理问题,那么每个人出了问题应该首先找谁来解决?
省长权利最大,自己出了问题自己解决,别人也没法知道; 可以认为在关系表里省长的父节点是自己。
Db代码
create table person(id int primary key, description varchar2(50));   
create table relationship(child int, parent int, primary key(child,parent));   
insert into person values(1,‘省长’);   
insert into person values(2,‘市长’);   
insert into person values(3,‘县长’);   
insert into person values(4,‘镇长’);   
insert into person values(5,‘村长’);   
insert into person values(6,‘平民’);   
...//省略的都是平民   
insert into person values(15,‘平民’);   
  
insert into relationship values(1,1); //关系如下   
insert into relationship values(2,1);   
insert into relationship values(3,1);   
insert into relationship values(5,2);   
insert into relationship values(6,2);   
insert into relationship values(4,3);   
insert into relationship values(7,3);   
insert into relationship values(8,3);   
insert into relationship values(9,3);   
insert into relationship values(10,4);   
insert into relationship values(11,4);   
insert into relationship values(12,4);   
insert into relationship values(13,4);   
insert into relationship values(14,5);   
insert into relationship values(15,5);  

查看一下关系树:
Oracle代码
select rpad('---',(level-1)*3,'---')||child relation_tree   
from relationship   
start with child=parent   
connect by nocycle prior child=parent; --结果如下   
RELATION_TREE   
------------------   
1  
---2  
------5  
---------14  
---------15  
------6  
---3  
------4  
---------10  
---------11  
---------12  
---------13  
------7  
------8  
------9  
  
已选择15行。  
select rpad('---',(level-1)*3,'---')||child relation_tree
from relationship
start with child=parent
connect by nocycle prior child=parent; --结果如下
RELATION_TREE
------------------
1
---2
------5
---------14
---------15
------6
---3
------4
---------10
---------11
---------12
---------13
------7
------8
------9

已选择15行。

查看父子关系情况:
Oracle代码
select child,parent   
from relationship   
start with child=parent   
connect by nocycle prior child=parent   
order by parent; --结果如下   
 CHILD     PARENT   
---------- ----------   
         1          1  
         2          1  
         3          1  
         5          2  
         6          2  
         4          3  
         8          3  
         7          3  
         9          3  
        11          4  
        12          4  
        10          4  
        13          4  
        14          5  
        15          5  
  
已选择15行。  
select child,parent
from relationship
start with child=parent
connect by nocycle prior child=parent
order by parent; --结果如下
CHILD     PARENT
---------- ----------
         1          1
         2          1
         3          1
         5          2
         6          2
         4          3
         8          3
         7          3
         9          3
        11          4
        12          4
        10          4
        13          4
        14          5
        15          5

已选择15行。

下面要看一看:每个人有事时,首先找到谁来处理?不能每个人有事都找省长吧。
下面的sql使用了oracle家的两个变态函数:first_value & connect_by_root
Oracle代码
select distinct child ,first_value(parent)over(partition by child order by lv) parent   
from(   
    select connect_by_root(r.child) child, p.description descr, level lv, r.parent   
    from person p ,relationship r   
    where p.id= r.parent   
    connect by nocycle prior r.parent=r.child   
 )   
where descr in('省长', '市长', '县长')   
order by parent,child; --结果如下   
     CHILD     PARENT   
---------- ----------   
         1          1  
         2          1  
         3          1  
         5          2  
         6          2  
        14          2  
        15          2  
         4          3  
         7          3  
         8          3  
         9          3  
        10          3  
        11          3  
        12          3  
        13          3  
  
已选择15行。  
select distinct child ,first_value(parent)over(partition by child order by lv) parent
from(
    select connect_by_root(r.child) child, p.description descr, level lv, r.parent
from person p ,relationship r
where p.id= r.parent
connect by nocycle prior r.parent=r.child
)
where descr in('省长', '市长', '县长')
order by parent,child; --结果如下
     CHILD     PARENT
---------- ----------
         1          1
         2          1
         3          1
         5          2
         6          2
        14          2
        15          2
         4          3
         7          3
         8          3
         9          3
        10          3
        11          3
        12          3
        13          3

已选择15行。

这个sql到底行不行,再加条数据看看
Db代码
insert into person values(333,‘县长’);   
insert into person values(555,‘村长’);   
insert into person values(666,‘平民’);    
insert into person values(777,‘平民’);   
  
insert into relationship values(333,1);   
insert into relationship values(555,333);   
insert into relationship values(666, 555);   
insert into relationship values(777,666);   


select * from mytable
  where 1=1
start with name like '%起始节点%'
connect by prior id = pid
 
  由子节点查询所以根节点
select * from mytable
  where 1=1
start with name like '%起始节点%'
connect by prior pid = id
 
   以上代码看是没有问题但经过本人验证会查询出不相关的节点,各种尝试都不能解决,只能妥协了
 
    select * from mytable
  where 1=1
start with id in (select id from mytable where name like '%起始节点%')
connect by prior pid = id

现有表:
id(不重复)   父级id         地区名字         级别
dist_id             parent_id      dist_name     dist_type
1                           0                        中国               0
2                           1                        北京               1
52                         2                        北京               2
500                      52                     朝阳区            3
501                      52                     东城区            3
3                          1                          安徽              1
36                        3                          安庆             2
399                     36                         大观区         3
……………………………………………………
就是这样的表,省市区都在一张表里面,现在想查询出这样的:
id             父级id          省            市            区              级别
2                     1                         北京                              1
52                   2                        北京                               2
500                52                       北京          朝阳区        3
501                52                       北京          东城区        3

WITH dep AS(

 SELECT 6 DEPID,'项目测试部' DEPNAME,2 UPPERDEPID FROM dual UNION ALL

 SELECT 0, '总经办', null FROM dual UNION ALL

 SELECT 1, '开发部', 0 FROM dual UNION ALL

 SELECT 2, '测试部', 0 FROM dual UNION ALL

 SELECT 3, 'Sever开发部', 1 FROM dual UNION ALL

 SELECT 4, 'Client开发部', 1 FROM dual UNION ALL

 SELECT 5, 'TA测试部', 2 FROM dual

 )

 SELECT RPAD(' ', 2 * (LEVEL - 1), '-') || DEPNAME "DEPNAME",

        CONNECT_BY_ROOT DEPNAME "ROOT",

        CONNECT_BY_ISLEAF "ISLEAF",

        LEVEL,

        SYS_CONNECT_BY_PATH(DEPNAME, '/') "PATH"

   FROM DEP

  START WITH UPPERDEPID IS NULL

 CONNECT BY PRIOR DEPID = UPPERDEPID;

WITH test AS(

 SELECT '1' dist_id,'0' parent_id,'中国' dist_name, '0' dist_type FROM dual UNION ALL

  SELECT '2' dist_id,'1' parent_id,'北京' dist_name, '1' dist_type FROM dual UNION ALL

   SELECT '52' dist_id,'2' parent_id,'北京' dist_name, '2' dist_type FROM dual UNION ALL

    SELECT '500' dist_id,'52' parent_id,'朝阳区' dist_name, '3' dist_type FROM dual UNION ALL

     SELECT '501' dist_id,'52' parent_id,'东城区' dist_name, '3' dist_type FROM dual UNION ALL

SELECT '3' dist_id,'1' parent_id,'安徽' dist_name, '1' dist_type FROM dual UNION ALL

SELECT '36' dist_id,'3' parent_id,'安庆' dist_name, '2' dist_type FROM dual UNION ALL

SELECT '399' dist_id,'36' parent_id,'大观区' dist_name, '3' dist_type FROM dual 

 ) 

 SELECT DIST_ID,

        DIST_NAME,

        REGEXP_SUBSTR(SYS_CONNECT_BY_PATH(DIST_NAME, '/'), '[^/]+', 1, 1) 国家,

        REGEXP_SUBSTR(SYS_CONNECT_BY_PATH(DIST_NAME, '/'), '[^/]+', 1, 2) 省,

        REGEXP_SUBSTR(SYS_CONNECT_BY_PATH(DIST_NAME, '/'), '[^/]+', 1, 3) 市,

        REGEXP_SUBSTR(SYS_CONNECT_BY_PATH(DIST_NAME, '/'), '[^/]+', 1, 4) 区, DIST_TYPE

   FROM TEST

  START WITH DIST_ID = '1'

 CONNECT BY PRIOR DIST_ID = PARENT_ID;

ORACLE提供了一种树形结构用来实现层次查询:
    START WITH :指定记录是根节点的条件。根节点可以有多个。
    CONNECT BY :指定记录之间是父节点和子节点关系的条件。查找出含有子节点的父节点的条件
    PRIOR :指定父节点记录的引用。
    SIBLINGS :指定树的排序。同一父节点下的兄弟节点的顺序。
  树在数据库表中的存储结构,如下:
create table TREE  (
   ID                   NUMBER                          not null,    //主键
   PID                  NUMBER                          not null,    //父节点id
   ORDER_ID             NUMBER                          not null,    //排序id
   NODE_NAME            VARCHAR2(100)                   not null,    //节点名称
   DEL                  VARCHAR2(5),                                 //删除标识  1:为删除
   constraint PK_TREE primary key (ID)
);
  实例sql语句如下:
SELECT * FROM tree WHERE del <> 1 START WITH pid = 0 AND del <> 1
CONNECT BY PRIOR id = pid AND del <> 1 ORDER SIBLINGS BY order_id
  查询出来的结果就是按树排序的记录集。
  如果用到了逻辑删除(假删除),那么上述sql语句中三处的del <> 1的意义是不同的。第一处是在表中全部记录中筛选出没有被标记删除的记录(缩短生成树的计算范围),第二处是筛选出根节点没有被标记删除的根节点的记录,第三处是是筛选出含有子节点的父节点没有被标记删除的父节点的记录

有一个结构如下:
WITH t AS (
SELECT '0' ID, '' pid,'' res FROM dual
UNION ALL
SELECT '00' ID,'0' pid,'' res FROM dual
UNION ALL
SELECT '01' ID,'0' pid,'' res FROM dual
UNION ALL
SELECT '000' ID,'00' pid,'A' res FROM dual
UNION ALL
SELECT '001' ID,'00' pid,'B' res FROM dual
UNION ALL
SELECT '010' ID,'01' pid,'C' res FROM dual
UNION ALL
SELECT '011' ID,'01' pid,'D' res FROM dual
)
SELECT lpad(' ',LEVEL*5)||ID ID,pid,res
FROM t
START WITH pid IS NULL
CONNECT BY PRIOR ID=pid


逻辑是叶子结点才有res数据,希望把叶子结点的数据逐级向上拼接,期望结果如下:

ID                     PID                   RES
0                                              A,B,C,D
  00                   0                      A,B
     000              00                     A
     001              00                     B
  01                   0                      C,D
     010              01                     C
     011              01                     D

有三张表 

表名:grand_father
表结构:grand_father_id         grand_grand_father_id  

表名:father
表结构:father_id         grand_father_id  

表名:son
表结构:son_id         father_id 

如何把这个树形结构放到一张表中,用select * from就可以查询的
注意:grand_grand_father_id有可能等于grand_father_id

select a.grand_father_id,b.father_id,c.son_id from grand_father a ,father b,son c where a.grand_father_id = b.grand_father_id and b.father_id = c.father_id

定义:
层次查询使用树的遍历,走遍含树形结构的数据集合,来获取树的层次关系报表的方法
树形结构的父子关系,你可以控制:
① 遍历树的方向,是自上而下,还是自下而上
② 确定层次的开始点(root)的位置
层次查询语句正是从这两个方面来确定的,start with确定开始点,connect by确定遍历的方向 www.2cto.com
2 语法:

注释:
① level是伪列,表示等级
② from后面只能是一个表或视图,对于from是视图的,那么这个view不能包含join
③ Where条件限制了查询返回的行,但是不影响层次关系,属于将节点截断,但是这个被截断的节点的下层child不受影响
④ prior是个形容词,可放在任何地方
⑤ 彻底剪枝条件应放在connect by;单点剪掉条件应放在where子句。但是,connect by的优先级要高于where,也就是sql引擎先执行connect by
⑥ 在start with中表达式可以有子查询,但是connect by中不能有子查询
3 遍历树:
㈠ Start with子句
Start with确定将哪行作为root,如果没有start with,则每行都当作root,然后查找其后代,这不是一个真实的查询。Start with后面可以使用子查询或者任何合法的条件表达式
例子:
[sql]
select level,id,manager_id,last_name,title from s_emp
start with title=(select title from s_emp where manager_id is null)
connect by prior id=manager_id;
㈡ Connect by子句
Connect by与prior确定一个层次查询的条件和遍历的方向(prior确定)
Connect by prior column_1=column_2;
其中prior表示前一个节点的意思,可以在connect by等号的前后,列之前,也可以放到select中的列之前 www.2cto.com
Connect by也可以带多个条件,比如 connect by prior id=manager_id and id>10
1. )自顶向下遍历:
先由根节点,然后遍历子节点。column_1表示父key,column_2表示子key。即这种情况下:connect by prior 父key=子key表示自顶向下,等同于connect by 子key=prior 父key.
例子:
[sql]
select level,employee_id,manager_id,last_name,job_id from s_emp
start with manager_id=100
connect by employee_id=prior manager_id;
2. )自底向上遍历:
先由最底层的子节点,遍历一直找到根节点。与上面的相反。Connect by之后不能有子查询,但是可以加其他条件,比如加上and id !=2等。这句话则会截断树枝,如果id=2的这个节点下面有很多子孙后代,则全部截断不显示。
例子:
[sql]
select level,employee_id,manager_id,last_name,job_id from s_emp
start with manager_id=100 www.2cto.com
connect by prior employee_id=manager_id and employee_id<>120;
4 使用level和lpad格式化报表:
Level是层次查询的一个伪列,如果有level,必须有connect by,start with可以没有
Lpad是在一个string的左边添加一定长度的字符,并且满足中间的参数长度要求,不满足自动添加
例子:
[sql]
select level,employee_id,manager_id,lpad(last_name,length(last_name)+(level*4)-4,&#39;_&#39;),job_id from s_emp
start with manager_id=100
connect by prior employee_id=manager_id and employee_id<>120
5 修剪branches:
where子句会将节点删除,但是其后代不会受到影响,connect by 中加上条件会将满足条件的整个树枝包括后代都删除。要注意,如果是connect by之后加条件正好条件选到根,那么结果和没有加一样
6 实际应用
1)查询每个等级上节点的数目
[sql]
先查看总共有几个等级:
select count(distinct level)
from s_emp
start with manager_id is null
connect by prior employee_id=manager_id
要查看每个等级上有多少个节点,只要按等级分组,并统计节点的数目即可,可以这样写:
select level,count(last_name)
from s_emp
start with manager_id is null
connect by prior employee_id=manager_id
group by level www.2cto.com
2)查看等级关系
比如给定一个具体的员工看是否对某个员工有管理权
[sql]
select level,a.* from
s_emp a
where first_name=&#39;Douglas&#39; --被管理的节点
start with manager_id is null --开始节点,即:根节点
connect by prior employee_id=manager_id
3)删除子树
比如有这样的需求,现在要裁员,将某个部门的员工包括经理全部裁掉
将id为2的员工管理的所有员工包括自己删除
[sql]
delete from s_emp where employee_id in(
elect employee_id from
s_emp a
start with employee_id=2 --从id=2的员工开始查找其子节点,把整棵树删除
connect by prior employee_id=manager_id)
4)找出每个部门的经理
[sql]
select level,a.* from
s_emp a www.2cto.com
start with manager_id is null
connect by prior employee_id=manager_id and department_id !=prior department_id;--当前行的dept_id不等于前一行的dept_id,即每个子树中选最高等级节点
5)查询一个组织中最高的几个等级
[sql]
select level,a.* from
s_emp a
where level <=2 &ndash;查找前两个等级
start with manager_id is null
connect by prior employee_id=manager_id and department_id !=prior department_id;
6)合计层次
有两个需求,一是对一个指定的子树subtree做累加计算salary,一是将每行都作为root节点,然后对属于这个节点的所有子节点累加计算salary。
[sql]
第一种很简单,求下sum就可以了,语句:
select sum(salary) from
s_emp a
start with id=2—比如从id=2开始
connect by prior id=manager_id;
第2个需求,需要用到第1个,对每个root节点求这个树的累加值,然后内部层次查询的开始节点从外层查询获得。
select last_name,salary,(
select sum(salary) from
s_emp www.2cto.com
start with id=a.id &ndash;让每个节点都成为root
connect by prior id=manager_id) sumsalary
from s_emp a;
7)找出指定层次中的叶子节点
Leaf(叶子)就是没有子孙的孤立节点。Oracle 10g提供了一个简单的connect_by_isleaf=1,0表示非叶子节点
[sql]
select level,id,manager_id,last_name, title from s_emp
where connect_by_isleaf=1 &ndash;表示查询叶子节点
start with manager_id=2
connect by prior id=manager_id;
7 10g新特性:
① 使用SIBLINGS关键字排序
如果使用order by排序会破坏层次,在oracle10g中,增加了siblings关键字的排序
语法:order siblings by <expre>
它会保护层次,并且在每个等级中按expre排序
例子:
[sql]
select level, www.2cto.com
employee_id,last_name,manager_id
from s_emp
start with manager_id is null
connect by prior employee_id=manager_id
order siblings by last_name;
② CONNECT_BY_ROOT
Oracle10g新增connect_by_root,用在列名之前表示此行的根节点的相同列名的值
例子:
[sql]
select connect_by_root last_name root_last_name, connect_by_root employee_id root_id,
employee_id,last_name,manager_id
from s_emp
start with manager_id is null
connect by prior employee_id=manager_id











 












猜你喜欢

转载自zhyp29.iteye.com/blog/2303065