一、概述

  1. Oracle中可以通过START WITH . . . CONNECT BY . . .子句来实现SQL的层次查询.
  2. 自从Oracle 9i开始,可以通过 SYS_CONNECT_BY_PATH 函数实现将父节点到当前行内容以“path”或者层次元素列表的形式显示出来。
  3. 自从Oracle 10g 中,还有其他更多关于层次查询的新特性 。例如,有的时候用户更关心的是每个层次分支中等级最低的内容。
    那么你就可以利用伪列函数CONNECT_BY_ISLEAF来判断当前行是不是叶子。如果是叶子就会在伪列中显示“1”,
    如果不是叶子而是一个分支(例如当前内容是其他行的父亲)就显示“0”。
  4. 在Oracle 10g 之前的版本中,如果在你的树中出现了环状循环(如一个孩子节点引用一个父亲节点),
    Oracle 就会报出一个错误提示:“ ORA-01436: CONNECT BY loop in user data”。如果不删掉对父亲的引用就无法执行查询操作。
    而在 Oracle 10g 中,只要指定“NOCYCLE”就可以进行任意的查询操作。与这个关键字相关的还有一个伪列——CONNECT_BY_ISCYCLE
    如果在当前行中引用了某个父亲节点的内容并在树中出现了循环,那么该行的伪列中就会显示“1”,否则就显示“0”。

层级查询的基本语法:

select [level],*  feom table_name  
start with 条件1
connect by [ nocycle ] prior 条件2
where 条件3 ORDER BY [ sibilings ] 排序字段

  说明:

  • start with condition1 是用来限制第一层的数据,或者叫根节点数据;以这部分数据为基础来查找第二层数据,然后以第二层数据查找第三层数据以此类推。
  • connect by [prior] id=parentid 连接条件,目的就是给出父子之间的关系是什么,根据这个关系进行递归查询
  • where 条件3---过滤条件,对所有返回的记录进行过滤。
  • order by 排序字段---对所有返回记录进行排序
  •   对prior说明:
    • connect by prior dept_id=par_dept_id :采用自上而下的搜索方式(先找父节点然后找叶子节点),比如说查找第二层的数据时用第一层数据的id去跟表里面记录的parentid字段进行匹配,匹配成功那么查找出来的就是第二层数据;
    • connect by dept_id=prior par_dept_id:采用自下而上的搜索方式(先找叶子节点然后找父节点)。 比如说用第一层数据的parentid去跟表记录里面的id进行匹配,匹配成功那么查找出来的就是第二层数据;
  • level关键字,LEVEL---伪列,用于表示树的层次 ,第一层是数字1,第二层数字2,依次递增。
  • CONNECT_BY_ROOT方法,能够获取第一层集结点结果集中的任意字段的值;例CONNECT_BY_ROOT(字段名)。

二、使用

1、基本用法

例1、 查询Raphaely及其的所有下属

select *  from employees
start with last_name = 'Raphaely'
connect by prior employee_id = manager_id; --找下属
-- connect by employee_id = prior manager_id;  --找上司,第一种,修改prior关键字位置
-- connect by prior manager_id = employee_id; --找上司,第二种,prior关键字不动 调换后面的 employee_id = manager_id 逻辑关系的顺序

例2、 查询除了Raphaely和他下属的所有员工

select * from employees
start with manager_id is null
connect by prior employee_id = manager_id and last_name <> 'Raphaely';

例3、 统计树形的层数

select count(distinct LEVEL)   from EMPLOYEES
start with MANAGER_ID is null
connect by prior EMPLOYEE_ID = MANAGER_ID;

例4、 过滤某些结果集,注意:where子句比connect by后执行。

查询Kochhar的所有下属中lastname为
Mavris雇员。

SELECT * FROM employees
WHERE last_name = 'Mavris'
START WITH last_name = 'Kochhar' --Kochhar的所有雇员
CONNECT BY PRIOR employee_id = manager_id;

例5、level伪列的使用,格式化层级

select lpad(' ',level*2,' ')||emp_name as name,emp_id,manager_id,salary,level from employee
start with manager_id=0
connect by prior emp_id=manager_id

2、SYS_CONNECT_BY_PATH() 函数

作用:  将父节点到当前节点的路径按照指定的模式展现出来,把一个父节点下的所有节点通过某个字符区分,然后链接在一个列中显示。

格式:

sys_connect_by_path(<列名>,<连接串>)
select sys_connect_by_path(t.dept_name,'-->'),t.dept_id, t.dept_name, t.dept_code,t.par_dept_id, level  from SYS_DEPT t
start with t.dept_id = 'e01d6'
connect by prior t.dept_id = t.par_dept_id
order by level, t.dept_code


3、CONNECT_BY_ISLEAF 伪列

作用:判断层次查询结果集中的行是不是叶子节点

返回值: 0表示不是叶子节点, 1表示是叶子节点

例:


4、CONNECT_BY_ROOT 字段x -> 找到该节点最顶端节点的字段x

select last_name "Employee", connect_by_root last_name "Manager",sys_connect_by_path(last_name, ' -> ') "Path" from hr.employees
where level > 1
connect by prior employee_id = manager_id
order by last_name, length("Path");

思考? 为什么不能加 start with ?  加了会有什么效果?

不加start with , 则每个节点都遍历一次 , connect_by_root 找到顶端的经理人会不同

而加了start with manager_id is null 则从树的根节点 King 开始遍历, 从而connect_by_root每个人的顶端的经理都是King

5、10g新特性 采用sibilings排序

作用: 因为使用order by排序会破坏层次,所以在oracle10g中,增加了siblings关键字的排序给叶子节点的关键字排序。

语法:

order siblings by <expre> asc|desc ;

它会保护层次,并且在每个等级中按expre排序

注意: order siblings by 必须紧跟着connect by,所以不能再用order by 了

例子:用order by,最后的结果是严格按照salary排序的,这样把层级关系都打乱了

select t.employee_id,t.manager_id,t.first_name,t.salary, sys_connect_by_path(t.first_name, '->'), level from hr.employees t
start with manager_id is null
connect by prior employee_id = manager_id
order by salary desc;

采用sibilings排序:结果的树结构没有被打乱,且没层级的sibilings都是按照salary排序的。

select t.employee_id,t.manager_id,t.first_name,t.salary,sys_connect_by_path(t.first_name, '->'),level from hr.employees t
start with manager_id is null
connect by prior employee_id = manager_id
order siblings by salary desc;

三、与row num 生成序列记录

rownum可用level代替。

1、简单序列:

select rownum from dual connect by rownum<=4

1
2
3
4

2、生成10-14的连续数(10开始,5行数据)

select 10+(rownum-1) from dual connect by rownum<=14-10+1

3、生成a-d的四个字母

select chr(ascii('a')+(rownum-1)) from dual connect by rownum<=ascii('d')-ascii('a')+1

4、生成2011-01-05至2011-01-10的日期

select to_date('2011-01-05','yyyy-mm-dd')+(rownum-1) from dual connect by rownum<=to_date('2011-01-10','yyyy-mm-dd')-to_date('2011-01-05','yyyy-mm-dd')+1

查询当前时间往前的12周的开始时间、结束时间、第多少周

select sysdate - (to_number(to_char(sysdate - 1, 'd')) - 1) - (rownum - 1) * 7 as startDate,
sysdate + (7 - to_number(to_char(sysdate - 1, 'd'))) - (rownum - 1) * 7 as endDate,
to_number(to_char(sysdate, 'iw')) - rownum + 1 as weekIndex
from dual
connect by level<= 12;--将level改成rownum可以实现同样的效果

  • d 表示一星期中的第几天

  • iw 表示一年中的第几周

5、字符串分割,由一行变为多行。

生成a1,b1,d1序列

select substr(id,
instr(id,',',1,rownum)+1,
instr(id,',',1,rownum+1) - instr(id,',',1,rownum)-1)--根据逗号的位置进行拆分
from (select ','||'a1,b1,d1'||',' as id from dual) --前后各加一个逗号
connect by rownum<=length(id)-length(replace(id,',',''))-1

或者

select REGEXP_SUBSTR('a1,b1,d1', '[^,]+', 1, rownum) as newport
from dual connect by rownum <= REGEXP_COUNT('a1,b1,d1', '[^,]+');

6、利用with子句生成测试数据

with temp as
(select 'a' as A,'b' as B from dual
union
select 'c' as C,'d' as D from dual
)
select * from temp;

7、日期维度数据生成方法。

select  to_date('2011-01-05','yyyy-mm-dd')+(rownum-1)  as ydate_date,
to_char(to_date('2011-01-05','yyyy-mm-dd')+(rownum-1),'yyyy') as ydate_month
from dba.tab_cols where to_date('2011-01-05','yyyy-mm-dd')+(rownum-1) != to_date('2060-01-05','yyyy-mm-dd')

Oracle递归查询connect by的更多相关文章

  1. Oracle递归查询start with connect by prior

    一.基本语法 connect by递归查询基本语法是: select 1 from 表格 start with ... connect by prior id = pId start with:表示以 ...

  2. Oracle递归查询,Oracle START WITH……CONNECT BY查询

    Oracle递归查询,Oracle START WITH……CONNECT BY查询,Oracle树查询 ================================ ©Copyright 蕃薯耀 ...

  3. mysql实现ORACLE的connect by prior父子递归查询

    oracle中有connect by prior ,可以实现父子递归查询.而mysql中没有这种功能,但我们可以变通实现. 比如一个表: Table Name: tb_Tree Id | Parent ...

  4. 【转载】Oracle递归查询:使用prior实现树操作【本文出自叶德华博客】

    本文标题:Oracle递归查询:使用prior实现树操作 本文链接:http://yedward.net/?id=41 本文版权归作者所有,欢迎转载,转载请以文字链接的形式注明文章出处. Oracle ...

  5. 【2016-11-7】【坚持学习】【Day22】【Oracle 递归查询】

    直接在oracle 递归查询语句 select * from groups start with id=:DeptId connect by prior superiorid =id 往下找 sele ...

  6. Oracle递归查询与常用分析函数

    最近学习oracle的一些知识,发现自己sql还是很薄弱,需要继续学习,现在总结一下哈. (1)oracle递归查询  start with ... connect by prior ,至于是否向上查 ...

  7. oracle中 connect by prior 递归算法 -- 理解

    oracle中 connect by prior 递归算法 -- 理解 http://blog.163.com/xxciof/blog/static/7978132720095193113752/  ...

  8. 12C 连接方式和 Oracle Easy Connect Naming method

    1.12C 连接方式 PDB is not an instance, so using SID in the connection string will not work. When the dat ...

  9. oracle使用connect by进行级联查询 树型菜单

    Oracle使用connect by进行级联查询 树型菜单(转) connect by可以用于级联查询,常用于对具有树状结构的记录查询某一节点的所有子孙节点或所有祖辈节点. 来看一个示例,现假设我们拥 ...

随机推荐

  1. 帮你培养类型思维TypeScript(一)

    前言:作为一名程序员,相信你已经熟练掌握了JavaScript语言,由于其应用领域非常的广泛,所以算得上是每一个程序员必须要掌握的语言.但是JavaScript自身的缺点,相信每一个程序员也是深有体会 ...

  2. Asp.Net Core中完成拒绝访问功能

    很多时候如果用户没有某个菜单的操作权限的话在页面是不应该显示出来的. @if (SignInManager.IsSignedIn(User) && User.IsInRole(&quo ...

  3. JVM(一) 内存结构

    JVM内存结构 方法区(JDK8以上叫元空间)和堆为线程共享区,虚拟机栈.本地方法栈及程序计数器为线程独占区,  还有一个没有在下图中体现的叫做直接内存(Direct Memory),不受JVM GC ...

  4. java实现邮箱发送邮件功能

    邮箱验证是一个很常见的功能了,基本上每个网站都会用的到,java也有专门的jar来处理邮件发送等服务,这里只是简单的实现一下发送邮件的功能,具体jar包就不再提供了,我会把所有需要引用的包都贴出来,方 ...

  5. Cookie,Session,Token详解

    Cookie,Session,Token详解 Cookie : ​ 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能. ​ Cookie由服务器生成,发 ...

  6. (一)Spring Security Demo 登陆与退出

    文章目录 配置springSecurityFilterChain过滤器 配置身份验证 加载配置 登陆项目 退出 下面的代码需要spring环境的支持: 看这个系列博客之前,需要这个博客,大概了解下 s ...

  7. PHP get和post向服务器发送请求

    1 .get请求 <?php //请求url地址 $token="xxx"; $url = "请求的地址"; //初始化curl $ch = curl_i ...

  8. 使用scrapy框架做赶集网爬虫

    使用scrapy框架做赶集网爬虫 一.安装 首先scrapy的安装之前需要安装这个模块:wheel.lxml.Twisted.pywin32,最后在安装scrapy pip install wheel ...

  9. AVR单片机教程——如何使用本教程

    这是一篇元教程(meta-tutorial)——其他教程教你怎么使用AVR单片机,本篇教程教你如何使用本系列教程. 我们的教程已经把板载LED讲完了,但是教会你的不应该只是如何使用LED.你应该已经知 ...

  10. 【转载】Maven入门实践

    Maven 确确实实是个好东西,用来管理项目显得很方便,但是如果是通过 Maven 来远程下载 JAR 包的话,我宿舍的带宽是4兆的,4个人共用,有时候用 Maven 来远程下载 JAR 包会显得很慢 ...