SQL之层次查询
层次查询是一种确定数据行间关系的一种操作手段。层次查询遍历的是一个树形结构。基本语法如下,以下语法嵌入到标准SQL中即可达到层次查询的目的:
level,... ...【注释:伪列,用于select子句中,根据数据所处的层次结构自动层次编号】 connect by [nocycle] prior 连接条件 【注释:指定数据之间的连接,其中nocycle需要结合connect_by_iscycle伪列确定出父子节点循环关系,不指定prior则仅显示第一层数据】 [start with 开始条件] 【注释:根节点开始条件】 |
一、测试数据
测试表依旧采用Oracle经典的scott模式下的emp表,结构如下:
EMP:
create table EMP ( EMPNO NUMBER(4) not null, ENAME VARCHAR2(10), JOB VARCHAR2(9), MGR NUMBER(4), HIREDATE DATE, SAL NUMBER(7,2), COMM NUMBER(7,2), DEPTNO NUMBER(2), SEX VARCHAR2(2) default '男' ) -- Create/Recreate primary, unique and foreign key constraints alter table EMP add constraint PK_EMP primary key (EMPNO) using index; alter table EMP add constraint FK_DEPTNO foreign key (DEPTNO) references DEPT (DEPTNO); |
SQL> select * from emp; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO SEX ----- ---------- --------- ----- ----------- --------- --------- ------ --- 7369 SMITH CLERK 7902 1980/12/17 800.00 20 男 7499 ALLEN SALESMAN 7698 1981/2/20 1600.00 300.00 30 女 7521 WARD SALESMAN 7698 1981/2/22 1250.00 500.00 30 女 7566 JONES MANAGER 7839 1981/4/2 2975.00 20 女 7654 MARTIN SALESMAN 7698 1981/9/28 1250.00 1400.00 30 女 7698 BLAKE MANAGER 7839 1981/5/1 2850.00 30 女 7782 CLARK MANAGER 7839 1981/6/9 2450.00 10 女 7788 SCOTT ANALYST 7566 1987/4/19 3000.00 20 男 7839 KING PRESIDENT 1981/11/17 5000.00 10 女 7844 TURNER SALESMAN 7698 1981/9/8 1500.00 0.00 30 女 7876 ADAMS CLERK 7788 1987/5/23 1100.00 20 男 7900 JAMES CLERK 7698 1981/12/3 950.00 30 女 7902 FORD ANALYST 7566 1981/12/3 3000.00 20 女 7934 MILLER CLERK 7782 1982/1/23 1300.00 10 男 14 rows selected |
二、层次查询示例
例:查询员工及其员工领导关系:
SQL> select empno, level, lpad('|-', level * 2, ' ') || ename as empname, mgr 2 from emp 3 connect by prior empno = mgr 4 start with mgr is null; EMPNO LEVEL EMPNAME MGR ----- ---------- ------------------------------ ----- 7839 1 |-KING 7566 2 |-JONES 7839 7788 3 |-SCOTT 7566 7876 4 |-ADAMS 7788 7902 3 |-FORD 7566 7369 4 |-SMITH 7902 7698 2 |-BLAKE 7839 7499 3 |-ALLEN 7698 7521 3 |-WARD 7698 7654 3 |-MARTIN 7698 7844 3 |-TURNER 7698 7900 3 |-JAMES 7698 7782 2 |-CLARK 7839 7934 3 |-MILLER 7782 14 rows selected |
1、connect_by_isleaf
在一个树形结构中,节点分为根节点和叶子节点两种,用户可以通过connect_by_isleaf伪列判断一个节点是根节点还是叶子节点,如果返回值为0,则表示根节点,返回1则表示叶子节点。
SQL> select empno, 2 level, 3 lpad('|-', level * 2, ' ') || ename as empname, 4 mgr, 5 decode(connect_by_isleaf, 0, '根节点', 1, ' 叶子节点') as isleaf 6 from emp 7 connect by prior empno = mgr 8 start with mgr is null; EMPNO LEVEL EMPNAME MGR ISLEAF ----- ---------- ------------------------------ ----- ------------ 7839 1 |-KING 根节点 7566 2 |-JONES 7839 根节点 7788 3 |-SCOTT 7566 根节点 7876 4 |-ADAMS 7788 叶子节点 7902 3 |-FORD 7566 根节点 7369 4 |-SMITH 7902 叶子节点 7698 2 |-BLAKE 7839 根节点 7499 3 |-ALLEN 7698 叶子节点 7521 3 |-WARD 7698 叶子节点 7654 3 |-MARTIN 7698 叶子节点 7844 3 |-TURNER 7698 叶子节点 7900 3 |-JAMES 7698 叶子节点 7782 2 |-CLARK 7839 根节点 7934 3 |-MILLER 7782 叶子节点 14 rows selected |
2、connect_by_root
取得某一字段在本层次中根节点的数据名称。
使用方法:connect_by_root 字段名称 [as 别名].
SQL> select empno, 2 level, 3 lpad('|-', level * 2, ' ') || ename as empname, 4 mgr, 5 decode(connect_by_isleaf, 0, '根节点', 1, ' 叶子节点') as isleaf, 6 connect_by_root ename as rootname 7 from emp 8 connect by prior empno = mgr 9 start with mgr is null; EMPNO LEVEL EMPNAME MGR ISLEAF ROOTNAME ----- ---------- ------------------------------ ----- ------------ ---------- 7839 1 |-KING 根节点 KING 7566 2 |-JONES 7839 根节点 KING 7788 3 |-SCOTT 7566 根节点 KING 7876 4 |-ADAMS 7788 叶子节点 KING 7902 3 |-FORD 7566 根节点 KING 7369 4 |-SMITH 7902 叶子节点 KING 7698 2 |-BLAKE 7839 根节点 KING 7499 3 |-ALLEN 7698 叶子节点 KING 7521 3 |-WARD 7698 叶子节点 KING 7654 3 |-MARTIN 7698 叶子节点 KING 7844 3 |-TURNER 7698 叶子节点 KING 7900 3 |-JAMES 7698 叶子节点 KING 7782 2 |-CLARK 7839 根节点 KING 7934 3 |-MILLER 7782 叶子节点 KING 14 rows selected |
3、sys_connect_by_path(column,char)
该函数根据层次节点关系,自动地将当前根节点中所有相关路径进行显示。
SQL> select empno, 2 level, 3 lpad('|=', level * 2, ' ') || sys_connect_by_path(ename, ' -> ') as empname, 4 mgr, 5 decode(connect_by_isleaf, 0, '根节点', 1, ' 叶子节点') as isleaf, 6 connect_by_root ename as rootname 7 from emp 8 connect by prior empno = mgr 9 start with mgr is null; EMPNO LEVEL EMPNAME MGR ISLEAF ROOTNAME ----- ---------- -------------------------------------------------- ----- ------------ ---------- 7839 1 |= -> KING 根节点 KING 7566 2 |= -> KING -> JONES 7839 根节点 KING 7788 3 |= -> KING -> JONES -> SCOTT 7566 根节点 KING 7876 4 |= -> KING -> JONES -> SCOTT -> ADAMS 7788 叶子节点 KING 7902 3 |= -> KING -> JONES -> FORD 7566 根节点 KING 7369 4 |= -> KING -> JONES -> FORD -> SMITH 7902 叶子节点 KING 7698 2 |= -> KING -> BLAKE 7839 根节点 KING 7499 3 |= -> KING -> BLAKE -> ALLEN 7698 叶子节点 KING 7521 3 |= -> KING -> BLAKE -> WARD 7698 叶子节点 KING 7654 3 |= -> KING -> BLAKE -> MARTIN 7698 叶子节点 KING 7844 3 |= -> KING -> BLAKE -> TURNER 7698 叶子节点 KING 7900 3 |= -> KING -> BLAKE -> JAMES 7698 叶子节点 KING 7782 2 |= -> KING -> CLARK 7839 根节点 KING 7934 3 |= -> KING -> CLARK -> MILLER 7782 叶子节点 KING 14 rows selected |
SQL> select empno, 2 level, 3 lpad('|=', level * 2, ' ') || sys_connect_by_path(ename, ' -> ') as empname, 4 mgr, 5 decode(connect_by_isleaf, 0, '根节点', 1, ' 叶子节点') as isleaf, 6 connect_by_root ename as rootname 7 from emp 8 connect by prior empno = mgr 9 and empno != 7698 10 start with mgr is null; EMPNO LEVEL EMPNAME MGR ISLEAF ROOTNAME ----- ---------- -------------------------------------------------- ----- ------------ ---------- 7839 1 |= -> KING 根节点 KING 7566 2 |= -> KING -> JONES 7839 根节点 KING 7788 3 |= -> KING -> JONES -> SCOTT 7566 根节点 KING 7876 4 |= -> KING -> JONES -> SCOTT -> ADAMS 7788 叶子节点 KING 7902 3 |= -> KING -> JONES -> FORD 7566 根节点 KING 7369 4 |= -> KING -> JONES -> FORD -> SMITH 7902 叶子节点 KING 7782 2 |= -> KING -> CLARK 7839 根节点 KING 7934 3 |= -> KING -> CLARK -> MILLER 7782 叶子节点 KING 8 rows selected |
4、order siblings by
在层次查询中,如果最终使用了order by子句进行排序,则会破坏最终的层次结构;而如果想保持层次结构同时在每层内进行排序则需要使用order siblings by子句。
SQL> select empno, 2 level, 3 lpad('|=', level * 2, ' ') || ename as sortname, 4 lpad('|=', level * 2, ' ') || sys_connect_by_path(ename, ' -> ') as empname, 5 mgr, 6 decode(connect_by_isleaf, 0, '根节点', 1, ' 叶子节点') as isleaf, 7 connect_by_root ename as rootname 8 from emp 9 connect by prior empno = mgr 10 start with mgr is null 11 order by ename; EMPNO LEVEL SORTNAME EMPNAME MGR ISLEAF ROOTNAME ----- ---------- -------------------- -------------------------------------------------- ----- ------------ ---------- 7876 4 |=ADAMS |= -> KING -> JONES -> SCOTT -> ADAMS 7788 叶子节点 KING 7499 3 |=ALLEN |= -> KING -> BLAKE -> ALLEN 7698 叶子节点 KING 7698 2 |=BLAKE |= -> KING -> BLAKE 7839 根节点 KING 7782 2 |=CLARK |= -> KING -> CLARK 7839 根节点 KING 7902 3 |=FORD |= -> KING -> JONES -> FORD 7566 根节点 KING 7900 3 |=JAMES |= -> KING -> BLAKE -> JAMES 7698 叶子节点 KING 7566 2 |=JONES |= -> KING -> JONES 7839 根节点 KING 7839 1 |=KING |= -> KING 根节点 KING 7654 3 |=MARTIN |= -> KING -> BLAKE -> MARTIN 7698 叶子节点 KING 7934 3 |=MILLER |= -> KING -> CLARK -> MILLER 7782 叶子节点 KING 7788 3 |=SCOTT |= -> KING -> JONES -> SCOTT 7566 根节点 KING 7369 4 |=SMITH |= -> KING -> JONES -> FORD -> SMITH 7902 叶子节点 KING 7844 3 |=TURNER |= -> KING -> BLAKE -> TURNER 7698 叶子节点 KING 7521 3 |=WARD |= -> KING -> BLAKE -> WARD 7698 叶子节点 KING 14 rows selected |
SQL> select empno, 2 level, 3 lpad('|=', level * 2, ' ') || ename as sortname, 4 lpad('|=', level * 2, ' ') || sys_connect_by_path(ename, ' -> ') as empname, 5 mgr, 6 decode(connect_by_isleaf, 0, '根节点', 1, ' 叶子节点') as isleaf, 7 connect_by_root ename as rootname 8 from emp 9 connect by prior empno = mgr 10 start with mgr is null 11 order siblings by ename; EMPNO LEVEL SORTNAME EMPNAME MGR ISLEAF ROOTNAME ----- ---------- -------------------- -------------------------------------------------- ----- ------------ ---------- 7839 1 |=KING |= -> KING 根节点 KING 7698 2 |=BLAKE |= -> KING -> BLAKE 7839 根节点 KING 7499 3 |=ALLEN |= -> KING -> BLAKE -> ALLEN 7698 叶子节点 KING 7900 3 |=JAMES |= -> KING -> BLAKE -> JAMES 7698 叶子节点 KING 7654 3 |=MARTIN |= -> KING -> BLAKE -> MARTIN 7698 叶子节点 KING 7844 3 |=TURNER |= -> KING -> BLAKE -> TURNER 7698 叶子节点 KING 7521 3 |=WARD |= -> KING -> BLAKE -> WARD 7698 叶子节点 KING 7782 2 |=CLARK |= -> KING -> CLARK 7839 根节点 KING 7934 3 |=MILLER |= -> KING -> CLARK -> MILLER 7782 叶子节点 KING 7566 2 |=JONES |= -> KING -> JONES 7839 根节点 KING 7902 3 |=FORD |= -> KING -> JONES -> FORD 7566 根节点 KING 7369 4 |=SMITH |= -> KING -> JONES -> FORD -> SMITH 7902 叶子节点 KING 7788 3 |=SCOTT |= -> KING -> JONES -> SCOTT 7566 根节点 KING 7876 4 |=ADAMS |= -> KING -> JONES -> SCOTT -> ADAMS 7788 叶子节点 KING 14 rows selected |
5、connect_by_iscycle
在进行层次查询时,最重要的是根据指定的数据确定数据间的层次关系,但是有时候会出现死循环的情况。在oracle中提供了connect_by_iscycle伪列用于判断是否出现了死循环,如果出现循环,则返回1,否则返回0.同时要判断是否为循环节点,需要nocycle的支持。
SQL> update emp set mgr = 7698 where empno = 7839; 1 row updated SQL> commit; Commit complete SQL> select empno, 2 level, 3 lpad('|=', level * 2, ' ') || ename as sortname, 4 decode(connect_by_isleaf, 1, '根节点', 0, ' 叶子节点') as isleaf, 5 decode(connect_by_iscycle, 1, '【X】存在循环', 0, '【√】没有循环') as iscycle, 6 mgr 7 from emp 8 connect by nocycle prior empno = mgr 9 start with mgr = 7839 10 order siblings by ename; EMPNO LEVEL SORTNAME ISLEAF ISCYCLE MGR ----- ---------- -------------------- ------------ -------------- ----- 7698 1 |=BLAKE 叶子节点 【√】没有循环 7839 7499 2 |=ALLEN 根节点 【√】没有循环 7698 7900 2 |=JAMES 根节点 【√】没有循环 7698 7839 2 |=KING 叶子节点 【X】存在循环 7698 7782 3 |=CLARK 叶子节点 【√】没有循环 7839 7934 4 |=MILLER 根节点 【√】没有循环 7782 7566 3 |=JONES 叶子节点 【√】没有循环 7839 7902 4 |=FORD 叶子节点 【√】没有循环 7566 7369 5 |=SMITH 根节点 【√】没有循环 7902 7788 4 |=SCOTT 叶子节点 【√】没有循环 7566 7876 5 |=ADAMS 根节点 【√】没有循环 7788 7654 2 |=MARTIN 根节点 【√】没有循环 7698 7844 2 |=TURNER 根节点 【√】没有循环 7698 7521 2 |=WARD 根节点 【√】没有循环 7698 7782 1 |=CLARK 叶子节点 【√】没有循环 7839 7934 2 |=MILLER 根节点 【√】没有循环 7782 7566 1 |=JONES 叶子节点 【√】没有循环 7839 7902 2 |=FORD 叶子节点 【√】没有循环 7566 7369 3 |=SMITH 根节点 【√】没有循环 7902 7788 2 |=SCOTT 叶子节点 【√】没有循环 7566 7876 3 |=ADAMS 根节点 【√】没有循环 7788 21 rows selected SQL> update emp set mgr = null where empno = 7839; 1 row updated SQL> commit; Commit complete |
SQL之层次查询的更多相关文章
- SQL Fundamentals: 子查询 || 行列转换(PIVOT,UNPIVOT,DECODE),设置数据层次(LEVEL...CONNECT BY)
SQL Fundamentals || Oracle SQL语言 子查询(基础) 1.认识子查询 2.WHERE子句中使用子查询 3.在HAVING子句中使用子查询 4.在FROM子句中使用子查询 5 ...
- Oracle层次查询
Oracle层次查询的语法如下: 下面根据两道“烧脑”的题具体来体现: 1. 根据时间先后顺序,十二星座的英文名称用逗号串起来为'Aries,Taurus,Gemini,Cancer,Leo,Virg ...
- oracle层次查询的陷阱
今天开发组同事找到我,说一个简单的层次查询非常慢,业务就是有一个存设备表连接关系的表,从node1连入,从node2连出,现在要找出node2的连出顺序,sql类似于: SELECT LEVEL ID ...
- 【转载】Oracle层次查询和分析函数
摘要 一组连续的数,去掉中间一些数,如何求出剩下的数的区间(即号段)?知道号段的起止,如何求出该号段内所有的数?知道一个大的号段范围和已经取过的号段,如何求出可用的号段?利用Oracle提供的强大的查 ...
- SQL基础-->层次化查询(START BY ... CONNECT BY PRIOR)[转]
--====================================================== --SQL基础-->层次化查询(START BY ... CONNECT BY ...
- SQL Fundamentals: 子查询 || 分析函数(PARTITION BY,ORDER BY, WINDOWING)
SQL Fundamentals || Oracle SQL语言 子查询(基础) 1.认识子查询 2.WHERE子句中使用子查询 3.在HAVING子句中使用子查询 4.在FROM子句中使用子查询 5 ...
- Oracle层次查询和分析函数在号段选取中的应用
转自:http://www.itpub.net/thread-719692-1-1.html 摘要一组连续的数,去掉中间一些数,如何求出剩下的数的区间(即号段)?知道号段的起止,如何求出该号段内所有的 ...
- SQL Fundamentals: 子查询 || WHERE,HAVING,FROM,SELECT子句中使用子查询,WITH子句
SQL Fundamentals || Oracle SQL语言 子查询(基础) 1.认识子查询 2.WHERE子句中使用子查询 3.在HAVING子句中使用子查询 4.在FROM子句中使用子查询 5 ...
- Oracle - 层次查询
如果表中含有层次数据,可以通过使用层次查询有序地查看层次数据. 语法: condition:指一个或多个表达式和逻辑(布尔)运算符的组合,并返回TRUE.FALSE或UNKNOWNstart with ...
随机推荐
- android sdk manager 代理设置
启动 Android SDK Manager ,打开主界面,依次选择「Tools」.「Options...」,弹出『Android SDK Manager - Settings』窗口: 在『Andro ...
- Socket网络编程--聊天程序(3)
上一小节,已经讲到可以每个人多说话,而且还没有限制,简单的来说,我们已经完成了聊天的功能了,那么接下来我们要实现什么功能呢?一个聊天程序至少应该支持一对多的通讯吧,接下来就实现多个客户端往服务器发送数 ...
- maven的配置及一些常用命令
一般来说,github上大多的java项目都是使用maven,ant等进行构建的.由于之前没有使用过maven,因此这几天对maven进行了简单的学习.古话说:“温故而知新”,一些命令长时间不使用都会 ...
- linux每日命令(24):Linux 目录结构
一. 简介 对于每一个Linux学习者来说,了解Linux文件系统的目录结构,是学好Linux的至关重要的一步.,深入了解linux文件目录结构的标准和每个目录的详细功能,对于我们用好linux系统只 ...
- 启动TDS LDAP 服务器遇到的问题总结
在启动TDS LDAP服务器时遇到一些问题,由于习惯使用Oracle数据库,而对DB2数据库比较陌生,在遇到这些问题时也是摸不到头脑,好在现在解决了,并把所遇到的问题罗列如下: 使用命令启动TDS L ...
- segMatch:基于3D点云分割的回环检测
该论文的地址是:https://arxiv.org/pdf/1609.07720.pdf segmatch是一个提供车辆的回环检测的技术,使用提取和匹配分割的三维激光点云技术.分割的例子可以在下面的图 ...
- Java如何找到一个单词的每一次匹配?
在Java编程中,如何查找字符串中特定单词的最后一个索引? 以下示例演示如何使用Matlass类的matchet.find()方法和Pattern类的Patter.compile()方法查找字符串中指 ...
- oracle 11G rac 11.2.0.1 打补丁9413827
这是升级到以后11.2.0.2.11.2.0.3.11.2.0.4的基础 主要参考两篇文章: Upgrade_11.2.0.1_GI_CRS_to_11.2.0.2_in_Linux.PDF文件 ht ...
- python加快数据处理的方法
1.一切数据库操作最好使用内网连接, 2.使用批量操作接口操作数据库,而不是多线程频繁操作单条数据 3.如果python进程的cpu使用率达到100%了,需要开启多进程.java单个进程cpu使用率在 ...
- 中文数据解码报错 UnicodeDecodeError: 'gbk' codec can't decode bytes in position 2-3: illegal multibyte sequence
UnicodeDecodeError: 'gbk' codec can't decode bytes in position 2-3: illegal multibyte sequence 失败原因: ...