Oracle Connect By Start With 总结==转帖

 Oracle Connect By Start With 总结==转帖 app

 

Oracle 实在太强了,本篇文章详细介绍了Oracle的递归查询语法,利用此语法,能够方便地实现递归的双向查询:ide

-- Tirle        : Recursion query for TREE with "connect by/start with"
-- Author       : Rake Gao
-- Create Date : 2005-08-22
-- Version      : 2.0
-- Last Modify : 2005-08-22测试

目 录
1、测试准备
2、实现各类查询要求
3、要点总结spa


正 文
1、测试准备
一、先假设有以下部门结构。
       1
     / \
    2    3 
   /\    /|\
4 5 6 7 8orm

二、而后创建测试表和数据。
drop table t_dept_temp;
create table t_dept_temp(
DEPT_ID    NUMBER(2)    NOT NULL,
PARENT_ID NUMBER(2)    ,
DEPT_NAME VARCHAR2(10) ,
AMOUNT     NUMBER(3)           --人数
);
delete t_dept_temp;
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (1,null,'1'    ,2);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (2,1   ,'1-2' ,15);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (3,1   ,'1-3' ,8);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (4,2   ,'1-2-4',10);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (5,2   ,'1-2-5',9);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (6,3   ,'1-3-6',17);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (7,3   ,'1-3-7',5);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (8,3   ,'1-3-8',6);
commit;排序

SQL> select * from t_dept_temp;递归

DEPT_ID PARENT_ID DEPT_NAME AMOUNT
------- --------- ---------- ------
      1           1               2
      2         1 1-2            15
      3         1 1-3             8
      4         2 1-2-4          10
      5         2 1-2-5           9
      6         3 1-3-6          17
      7         3 1-3-7           5
      8         3 1-3-8           6ci

三、调整一下输出格式
col DEPT_ID format A10;it

2、接下来实现各类查询要求
一、部门2及其全部下级部门。
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM t_dept_temp
CONNECT BY PARENT_ID = PRIOR DEPT_ID -- 找出全部PARENT_ID等于当前记录DEPT_ID的记录。
START WITH DEPT_ID = 2                -- 从部门2开始递归查询。
;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
2                  1 1-2            15
4                2 1-2-4          10
5                2 1-2-5           9io

二、部门4及其全部上级部门
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
CONNECT BY PRIOR PARENT_ID = DEPT_ID -- 找出全部DEPT_ID等于当前记录PARENT_ID的记录
START WITH DEPT_ID = 4               -- 从部门4开始递归查询。
;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
4                  2 1-2-4          10
2                1 1-2            15
    1                1               2

三、部门1的全部下级部门。
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
2                1 1-2            15
    4              2 1-2-4          10
    5              2 1-2-5           9
3                1 1-3             8
    6              3 1-3-6          17
    7              3 1-3-7           5
    8              3 1-3-8           6

四、部门1及其全部下级部门,可是不包括部门3及其下级部门。(排除树枝)
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID
         AND DEPT_ID <> 3    -- 不包括部门3及其下属部门(部门3和六、七、8都没出现)
;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
2                1 1-2            15
    4              2 1-2-4          10
    5              2 1-2-5           9

五、部门1及其全部下级部门,可是仅不包括部门3。(排除节点)
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
WHERE DEPT_ID <>3          -- 仅仅不包括部门3(输出结果中,3的下级部门六、七、8仍是出现了)
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID -- 执行顺序where在connect by以后
;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
2                1 1-2            15
    4              2 1-2-4          10
    5              2 1-2-5           9
    6              3 1-3-6          17
    7              3 1-3-7           5
    8              3 1-3-8           6

六、部门1及其全部下级部门,且全部部门按照人数升序排列。
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID
ORDER BY AMOUNT ASC -- 排序在最后被执行,因此DEPT_ID彻底被打乱了,并且层级关系也打乱了。
;
-- In a hierarchical query, do not specify either ORDER BY or GROUP BY, 
-- as they will destroy the hierarchical order of the CONNECT BY results.
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
    7              3 1-3-7           5
    8              3 1-3-8           6
3                1 1-3             8
    5              2 1-2-5           9
    4              2 1-2-4          10
2                1 1-2            15
    6              3 1-3-6          17

七、部门1及其全部下级部门,每一个部门的下一级部门之间,按照人数降序排列。(有同一上级的那些部门???
-- If you want to order rows of siblings of the same parent, 
-- then use the ORDER SIBLINGS BY clause.
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID
ORDER SIBLINGS BY AMOUNT ASC -- 同属部门间排序

-- 输出结果可见,部门三、2做为一组进行排序,部门七、八、6一组,五、4一组。
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
3                1 1-3             8
    7              3 1-3-7           5
    8              3 1-3-8           6
    6              3 1-3-6          17
2                1 1-2            15
    5              2 1-2-5           9
    4              2 1-2-4          10

3、要点总结
一、子句的语法书写顺序。
select -> from -> where -> start with -> connect by -> order by
where写在connect by后面就不行,报错。

二、子句的执行顺序
from -> start with -> connect by -> where -> select -> order by
执行顺序where在connect by以后,能够从例5证实。
但是书写SQL语句的时候,却只能写前面,注意理解。

三、如何理解和记忆“CONNECT BY PRIOR PARENT_ID = DEPT_ID ”的含义呢?
如今看这个例子彷佛很直观,可是从此实际应用时,条件变化后,如何推断查询结果呢?
    这里我本身总结一种方法,前提是要理解SQL语句执行时,是一条一条记录来处理的。
每条知足START WITH语句条件的记录被依次取出,暂且把每次被取出处理的记录,称为当前记录。
“PRIOR PARENT_ID”代表从当前记录获得PARENT_ID,
而后" = DEPT_ID"说明找到表中全部DEPT_ID等于当前记录PARENT_ID的记录,也就是找当前记录PARENT_ID所指向的记录。
    由于PARENT_ID的取值含义是上级节点,因此说明是向树的根节点方向的搜索。(个人上级是谁?)
    反之,若是是“CONNECT BY PARENT_ID = PRIOR DEPT_ID”,“PRIOR”在DEPT_ID一边,就是找全部PARENT_ID等于当前记录DEPT_ID的记录,是向树的叶子方向的搜索。(谁的上级是我?)
    找到结果记录集之后,从第一条记录开始递归处理,依此类推。

四、前序遍历
因为是递归处理,从例3能够看出,树的根节点向叶子节点递归查询时,查询节点的顺序是按照树的前序遍历进行的。

五、排序
例6和例7说明了两种排序的区别。
In a hierarchical query, do not specify either ORDER BY or GROUP BY, as they will destroy the hierarchical order of the CONNECT BY results. If you want to order rows of siblings of the same parent, then use the ORDER SIBLINGS BY clause. See order_by_clause.

六、伪列LEVEL
只能随CONNECT BY子句一块儿使用,是一个整数,表明递归的层次深度。也就是节点在树中所处深度。
根节点时等于1,根节点的叶子节点的深度等于2,依此类推。
LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID 正是利用了LEVEL来为每一个层级的字段提供不一样的缩进。


over

 

 

----btw  能够理解为从新排序。

相关文章
相关标签/搜索