Oracle递归查询connect by
一、概述
- Oracle中可以通过START WITH . . . CONNECT BY . . .子句来实现SQL的层次查询.
- 自从Oracle 9i开始,可以通过 SYS_CONNECT_BY_PATH 函数实现将父节点到当前行内容以“path”或者层次元素列表的形式显示出来。
- 自从Oracle 10g 中,还有其他更多关于层次查询的新特性 。例如,有的时候用户更关心的是每个层次分支中等级最低的内容。
那么你就可以利用伪列函数CONNECT_BY_ISLEAF来判断当前行是不是叶子。如果是叶子就会在伪列中显示“1”,
如果不是叶子而是一个分支(例如当前内容是其他行的父亲)就显示“0”。 - 在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的更多相关文章
- Oracle递归查询start with connect by prior
一.基本语法 connect by递归查询基本语法是: select 1 from 表格 start with ... connect by prior id = pId start with:表示以 ...
- Oracle递归查询,Oracle START WITH……CONNECT BY查询
Oracle递归查询,Oracle START WITH……CONNECT BY查询,Oracle树查询 ================================ ©Copyright 蕃薯耀 ...
- mysql实现ORACLE的connect by prior父子递归查询
oracle中有connect by prior ,可以实现父子递归查询.而mysql中没有这种功能,但我们可以变通实现. 比如一个表: Table Name: tb_Tree Id | Parent ...
- 【转载】Oracle递归查询:使用prior实现树操作【本文出自叶德华博客】
本文标题:Oracle递归查询:使用prior实现树操作 本文链接:http://yedward.net/?id=41 本文版权归作者所有,欢迎转载,转载请以文字链接的形式注明文章出处. Oracle ...
- 【2016-11-7】【坚持学习】【Day22】【Oracle 递归查询】
直接在oracle 递归查询语句 select * from groups start with id=:DeptId connect by prior superiorid =id 往下找 sele ...
- Oracle递归查询与常用分析函数
最近学习oracle的一些知识,发现自己sql还是很薄弱,需要继续学习,现在总结一下哈. (1)oracle递归查询 start with ... connect by prior ,至于是否向上查 ...
- oracle中 connect by prior 递归算法 -- 理解
oracle中 connect by prior 递归算法 -- 理解 http://blog.163.com/xxciof/blog/static/7978132720095193113752/ ...
- 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 ...
- oracle使用connect by进行级联查询 树型菜单
Oracle使用connect by进行级联查询 树型菜单(转) connect by可以用于级联查询,常用于对具有树状结构的记录查询某一节点的所有子孙节点或所有祖辈节点. 来看一个示例,现假设我们拥 ...
随机推荐
- Jira强制退出时(如意外停电)再启动报Locked错误的几个解决办法
查看jira_home的路径在/opt/atlassian/jira/atlassian-jira/WEB-INF/classes/jira-application.properties文件中查看 方 ...
- [学习笔记] 下载、安装、启动 Eclipse(OEPE)
OEPE 的全称是: Oracle Enterprise Pack for Eclipse 截止目前的最新版本是:(12.2.1.9) 下载地址:(需要在甲骨文官网注册一个账户才能下载) https: ...
- 039 Android ShareSDK实现分享功能
1.参考文献: https://blog.csdn.net/augfun/article/details/86551294 http://wiki.mob.com/sdk-share-android- ...
- Echarts 不能百分比显示或显示有问题
1,设折线图宽为100%(如:容器div的class=“RiBarBot”宽为880px),刚初始化时隐藏折线图(或后期刷新.隐藏与显示折线图时),当点击显示折线图时,获取到的宽只有100px,并不是 ...
- Spring Boot 入门(九):集成Quartz定时任务
本片文章续<Spring Boot 入门(八):集成RabbitMQ消息队列>,关于Quartz定时任务请参考<Quartz的基本使用之入门(2.3.0版本)> spring ...
- PAT甲级题分类汇编——理论
本文为PAT甲级分类汇编系列文章. 理论这一类,是让我觉得特别尴尬的题,纯粹是为了考数据结构而考数据结构.看那Author一栏清一色的某老师,就知道教数据结构的老师的思路就是和别人不一样. 题号 标题 ...
- 知识不是来炫耀的,而是来分享的-----现在的人们却…似乎开始变味了…
我讨厌那些自以为是的人,哪些只有远大抱负却不付出的混蛋,我讨厌那些老生欺负小生,讨厌以大欺小,讨厌别人把知识拿来炫耀. 我自己也不愿做这类人,我渴望看到成功,我不怕一意孤行,我不怕失败,我只怕自己做的 ...
- Docker 学习笔记(二):Dockerfile 定制镜像
镜像的定制实际上就是定制每一层所添加的配置.文件. 如果我们可以把每一层修改.安装.构建.操作的命令都写入一个脚本,用这个脚本来构建.定制镜像,那么之前提及的无法重复的问题.镜像构建透明性的问题.体积 ...
- entity-framework-core – 实体框架核心RC2表名称复数
参考地址:https://docs.microsoft.com/zh-cn/ef/core/modeling/relational/tables http://www.voidcn.com/artic ...
- CTR预估-GBDT与LR实现
1.来源 本质上 GBDT+LR 是一种具有 stacking 思想的二分类器模型,所以可以用来解决二分类问题.这个方法出自于 Facebook 2014 年的论文 Practical Lessons ...