Oracle Connect By Start With 总结==转帖

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

-- 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、先假设有如下部门结构。
       1
     / \
    2    3 
   /\    /|\
4 5 6 7 8

2、然后建立测试表和数据。
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           6

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

二、接下来实现各种查询要求
1、部门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           9

2、部门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

3、部门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

4、部门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和6、7、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

5、部门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的下级部门6、7、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

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

7、部门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 -- 同属部门间排序

-- 输出结果可见,部门3、2作为一组进行排序,部门7、8、6一组,5、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

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

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

3、如何理解和记忆“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的记录,是向树的叶子方向的搜索。(谁的上级是我?)
    找到结果记录集以后,从第一条记录开始递归处理,依此类推。

4、前序遍历
由于是递归处理,从例3可以看出,树的根节点向叶子节点递归查询时,查询节点的顺序是按照树的前序遍历进行的。

5、排序
例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.

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

over

----btw  可以理解为重新排序。

转载于:https://blog.51cto.com/young0/448191

Oracle Connect By Start With 总结==转帖相关推荐

  1. oracle+connect+by+level,oracle connect by用法篇

    1.基本语法 select * from table [start with condition1] connect by [prior] id=parentid1 2 一般用来查找存在父子关系的数据 ...

  2. oracle connect权限6,Oracle 19c 升级19.6 RU 导致权限异常 gipcInternalConnectSync: failed sync request 解决方法...

    这2天一直在测试RAC 环境的19.6 的RU升级问题.因为opatchauto 一起升级GI 和DB 操作导致CRS 权限异常, CRS 无法启动. 根据提示,之前已经处理过一批错误,如下: htt ...

  3. db2 如何 将 oracle CONNECT BY 移植到 DB2

     将 CONNECT BY 移植到 DB2 http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0510rielau ...

  4. Oracle connect by与level的使用

    1.level是什么? level是在树形结构中.表示层级的伪列. 1.1树形结构 Oracle支持树形结构的查询,用关键字connect by 表示. connect by表示在构造树形结构时,上下 ...

  5. oracle connect by优化小探

    前一篇介绍了connect by的用法 https://blog.csdn.net/u011165335/article/details/82822224 这里在看看如何优化: 环境跟上一篇的一样:1 ...

  6. oracle connect by用法篇

    原文链接:https://blog.csdn.net/wang_yunj/article/details/51040029 1.基本语法 select * from table [start with ...

  7. oracle connect by prior 树形结构

    为了更好的查询一个树状结构的表,在Oracle的PL/SQL中提供乐一个诱人的特性--CONNECT BY子句.它大大的方便了我们查找树状表:遍历一棵树.寻找某个分支--,但还是存在一些不足.在Ora ...

  8. oracle connect by用法

    先用scott用户下的emp表做实验. emp表有个字段,一个是empno(员工编号),另一个是mgr(上级经理编号) 下面是表中所有数据 1 select * from emp start with ...

  9. oracle:connect by start

    select * from t_s_fun a CONNECT BY C_FUN_CODE = PRIOR C_FUN_CODE_PSTART WITH C_FUN_CODE IN ('AccSubj ...

最新文章

  1. VK Cup 2012 Qualification Round 2 C. String Manipulation 1.0 字符串模拟
  2. PYTHON2.day03
  3. 视频直播技术:最大限度保障流畅性和清晰度
  4. java实现数字转mac,Java Ethernet.getSourceMAC方法代码示例
  5. jdk8 calendar_JDK 8的Calendar.Builder
  6. Rabbitmq学习笔记007---Centos7下安装rabbitmq_测试通过
  7. 【优化算法】蛾群优化算法(MSA)【含Matlab源码 1451期】
  8. qt之解决qtableview加载百万行数据卡顿问题
  9. Java UDP 客户端服务器程序示例
  10. 抖音sdk,抖音开发api接口
  11. 斐波那契数列的几种求解方法
  12. C语言入夏标志,[二级C语言程序设计.docx
  13. MyCP.java蓝墨云班课
  14. 零基础学彩铅——下午茶(含详细步骤)
  15. PMP考试中常见的翻译问题
  16. C#发送邮件(阿里企业邮箱示例 包括各个类型的服务器及端口配置)
  17. 通信类会议期刊排名(转)
  18. 树结构(Java实现)
  19. 会议纪要的正确记录姿势
  20. 【Python】字节码与dis模块

热门文章

  1. MFC中静态文本控件显示的几种实现方式
  2. Happy Birthday
  3. 美赛开赛在即,你准备好了吗?
  4. bee 字符串转int_Beego在views中格式化显示时间(int64转string)
  5. MySQL 高级 - 存储过程 - 概述
  6. Nginx的SSL相关指令
  7. RabbitMQ fanout交换机(消费者)
  8. 基于Xml 的IOC 容器-解析配置文件路径
  9. TCP/IP的四层负载均衡
  10. 使用PyCharm定义QQ变量