Oracle--(Hierarchical Queries)层级查询



内容来自: Oracle® Database SQL Language Reference 11g Release 2 (11.2) E41084-03。

empolyees表来自hr方案,warehouses来自oe方案。



如果表中包含层级数据,可以使用层级查询子句按层级顺序选择数据行,形成层级树,形式如下:

下面是层级查询字句的火车图:

START WITH:指定层级的根行。即根据条件选取一些行,以这些行做最顶级行,获取子行。

CONNECT BY:指定层级中父行与子行关系。

一个层级查询的例子:

SELECT last_name, employee_id, manager_id, LEVEL
FROM employees
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id
ORDER SIBLINGS BY last_name;

查询结果:

LAST_NAME                 EMPLOYEE_ID MANAGER_ID LEVEL
------------------------- ----------- ---------- ----------

King                      100                    1

Cambrault                 148          100       2

Bates                     172          148       3

Bloom                     169          148       3

Fox                       170          148       3

Kumar                     173          148       3

Ozer                      168          148       3

Smith                     171          148       3

De Haan                   102          100       2

Hunold                    103          102       3

Austin                    105          103       4

Ernst                     104          103       4

Lorentz                   107          103       4

Pataballa                 106          103       4

Errazuriz                 147          100       2

Ande                      166          147       3

Banda                     167          147       3

...

Oracle按如下方式处理层级查询:

  • 如果存在连接,首先计算连接,无论连接在FROM子句中还是在WHERE子句中
  • 计算CONNECT BY 条件
  • 计算任何余下的WHERE子句

接下来,Oracle将使用上面计算获取的信息形成层级:

  1. Oracle选择满足START WITH 条件的根记录
  2. Oracle选择每条根记录的子行,每条子行满足CONNECT BY条件
  3. Oracle选择上一步子行的逐代子行。即Oracle首先选择上一步子行的子行,然后在选取这些子行的子行,一次向下。Oracle总是计算当前父行的CONNECT BY条件来选择子行。什么意思呢?一个包含层级数据的表中,包含了两个具有层级关系的列,如:EMPLOYEE_ID和MANAGER_ID,EMPLOYEE_ID是当前行的标识,而MANAGER_ID是父行的标识(即父行的EMPLOYEE_ID)。如何指定这个关系呢?Oracle使用了Prior操作符,PRIOR是一元操作符,作用于紧跟在它后面的字段名,如PRIOR EMPLOYEE_ID = MANAGER_ID,把该条件用于当前父行,PRIOR操作符导致Oracle取父行的EMPLOYEE_ID列的值,然后取子行的MANAGER_ID列的值与之比较,从而选出当前父行的子行。
  4. 如果查询包含一个无连接的WHERE子句,Oracle从层级中除去不满足WHERE子句的行。Oracle分别为每一行计算该条件,而不是当某一行不符合条件时,就移除它的所有子行。
  5. Oracle以层序的方式返回行。如图,返回记录的次序为1,2,3,4,5,6,7,8,9,10,11,12。看来,Oracle对每一次获取的子行进行了某种处理,而不是简单的追加。

下面是一些层级查询的例子:

1、CONNECT BY

这个例子仅使用CONNECT BY 子句定义雇员和经理的关系

SELECT employee_id, last_name, manager_id
FROM employees
CONNECT BY PRIOR employee_id = manager_id;

查询结果(部分):

2、LEVEL

这个例子在查询结果中使用了LEVEL伪劣显示行在树关系中的层级

SELECT employee_id, last_name, manager_id, LEVEL
FROM employees
CONNECT BY PRIOR employee_id = manager_id;

查询结果(部分):

3、START WITH

这个例子添加了START WITH子句指定起始根行,使用SIBLINGS关键字对兄弟节点(同一父行的子行)排序

SELECT last_name, employee_id, manager_id, LEVEL
FROM employees
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id
ORDER SIBLINGS BY last_name;

查询结果(部分):

4、LOOP

在上一个例子中,King没有上级领导,在他的员工中,有一个叫John Russell的部门(代码80)领导,现在更新King的领导为John Russell

UPDATE employees SET manager_id = 145
WHERE employee_id = 100;

执行语句:

SELECT last_name "Employee",
LEVEL, SYS_CONNECT_BY_PATH(last_name, ‘/‘) "Path"
FROM employees
WHERE level <= 3 AND department_id = 80
START WITH last_name = ‘King‘
CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 4

报告错误:

ORA-01436: 用户数据中的 CONNECT BY 循环

错误的原因是King即是John Russell的领导又是他的员工,这就产生了一个循环,遇到这种情况Oracle会报告错误。但是,如果在CONNECT BY子句中使用NOCYCLE参数让Oracle返回结果。使用CONNECT_BY_ISCYCLE伪列可以显示哪些行包含循环。

执行语句:

SELECT last_name "Employee", CONNECT_BY_ISCYCLE "Cycle",
LEVEL, SYS_CONNECT_BY_PATH(last_name, ‘/‘) "Path"
FROM employees
WHERE  department_id = 80
START WITH last_name = ‘King‘
CONNECT BY NOCYCLE PRIOR employee_id = manager_id AND LEVEL <= 3
ORDER BY "Employee", "Cycle", LEVEL, "Path";

查询结果:

可见,Oracle去掉了无限循环的部分。

5、CONNECT_BY_ISLEAF

这是一个伪列,显示行在层级树中是否为叶子节点,1代表叶子节点,非1代表非叶子节点。

执行语句:

SELECT last_name "Employee",
LEVEL, SYS_CONNECT_BY_PATH(last_name, ‘/‘) "Path"
FROM employees
WHERE department_id=80  and CONNECT_BY_ISLEAF=1
START WITH last_name = ‘King‘
CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 3;

查询结果:

这些3级节点全部为叶子节点,King出现在查询结果中,是因为我们在START WITH中指定了起始根行。

Oracle文档中给出了一个有趣的例子,展示如何使用层级查询把表中的一列数据转换为用逗号分隔的列表。执行语句:

SELECT LTRIM(SYS_CONNECT_BY_PATH (warehouse_id,‘,‘),‘,‘) FROM
(SELECT ROWNUM r, warehouse_id FROM warehouses)
WHERE CONNECT_BY_ISLEAF = 1
START WITH r = 1
CONNECT BY r = PRIOR r + 1
ORDER BY warehouse_id;

查询结果:

CONNECT BY r = PRIOR r + 1 子句指定了行的父子关系,如在当前父行中,PRIOR运算符取出r值,然后加1,查询满足r的值等于r+1的行,即从第一行开始,紧邻的两行均形成父子关系,前一行为父行,后一行为子行,由于r的特殊性(单向有序列表1,2,3,4…),实际上形成的树就是一个列表。运用SYS_CONNECT_BY_PATH显示每个节点的路径,使用CONNECT_BY_ISLEAF = 1条件仅选择叶子节点。

在这个例子中,每行的warehouse_id 恰好等于ROWNUM,可以换成其他列,形成不同的列表。

6、CONNECT_BY_ROOT

这个例子显示部门110的每个雇员的姓、每个雇员所有上级经理、雇员与经理的层级数、雇员与经理之间的路径。

执行语句:

SELECT last_name "Employee", CONNECT_BY_ROOT last_name "Manager",
LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(last_name, ‘/‘) "Path"
FROM employees
WHERE LEVEL > 1 and department_id = 110
CONNECT BY PRIOR employee_id = manager_id
ORDER BY "Employee", "Manager", "Pathlen", "Path";

查询结果:

时间: 2024-07-28 22:07:01

Oracle--(Hierarchical Queries)层级查询的相关文章

oracle中的层级查询用mysql替换

Oracle的Start with...Connect By实现了树的递归查询,但是现在要求用MYSQL也实现相同的递归查询树的功能.这个功能是我从以前从未使用到过的,于是,我上网查询.找了一些资料开始做了起来. 原始的oracle语句为 select '|'||c.seq_cate||'|' from osr_category c start with c.seq_cate = #serviceCategory# connect by prior c.seq_cate = c.parent_i

用SYS_CONNECT_BY_PATH进行层级查询时的排序问题

用SYS_CONNECT_BY_PATH进行层级查询时, 对同一级别的节点进行排序,可以加order SIBLINGS by 子句实现 WITH N2 AS( SELECT n.ID, org."ParentID", n."NodeName", n."Sort" FROM "Organize" org LEFT JOIN "Node" n ON n."ID"=org."Node

Oracle SQL语言之查询语句_超越OCP精通Oracle视频教程培训29

Oracle SQL语言之查询语句_超越OCP精通Oracle视频教程培训29 本课程介绍: Oracle视频教程,风哥本套oracle教程培训是<<Oracle数据库SQL语言实战培训教程>>的第4/5套:Oracle SQL语言之查询语句.主要学习Oracle数据库SQL查询限制排序.Oracle SQL联接查询.Oracle SQL子查询等. 视频学习地址: http://edu.51cto.com/course/course_id-8047.html Oracle SQL语

彻底搞懂oracle的标量子查询

oracle标量子查询和自定义函数有时用起来比较方便,而且开发人员也经常使用,数据量小还无所谓,数据量大,往往存在性能问题. 以下测试帮助大家彻底搞懂标量子查询. SQL> create table a (id int,name varchar2(10)); Table created. SQL> create table b (id int,name varchar2(10)); Table created. SQL> insert into a values (1,'a1'); 1

ORACLE PATCH 版本的查询 PL/SQL

--ORACLE PATCH 版本的查询 PL/SQL SELECT DD.PATCH_NAME,        PP.CREATION_DATE,        PP.DRIVER_FILE_NAME,        LANG.LANGUAGE  FROM AD_PATCH_DRIVERS PP,        AD_APPLIED_PATCHES DD,        AD_PATCH_DRIVER_LANGS LANG WHERE PP.APPLIED_PATCH_ID = DD.APPL

Oracle字符集的查看查询和Oracle字符集的设置修改

本文主要讨论以下几个部分:如何查看查询oracle字符集. 修改设置字符集以及常见的oracle utf8字符集和oracle exp 字符集问题. 一.什么是Oracle字符集 Oracle字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包容关系.ORACLE 支持国家语言的体系结构允许你使用本地化语言来存储,处理,检索数据.它使数据库工具,错误消息,排序次序,日期,时间,货币,数字,和日历自动适应本地化语言和平台. 影响Oracle数据库字符集最重要的参数是NLS_LANG参数.

JDBC操作Oracle,根据日期查询

方法一: 1 SimpleDateFormat dateformat=new SimpleDateFormat("yyyy-MM-dd"); 2 String today=dateformat.format(new Date()); 3 4 String delSql = "delete from ssd_pms_forecast_recode where forecasteNum = '"+forecastNum+"' and forecasteTime

[转]Oracle DB 使用子查询来解决查询

? 定义子查询 ? 描述子查询可以解决的问题类型 ? 列出子查询的类型 ? 编写单行和多行子查询 ? 子查询:类型.语法和准则 ? 单行子查询: – 子查询中的组函数 – 带有子查询的HAVING子句 ? 多行子查询 – 使用ALL或ANY运算符 ? 使用EXISTS运算符 ? 子查询中的空值 使用子查询解决问题 谁的薪金高于Abel 的薪金? 子查询: Abel 的薪金是多少? 主查询: 哪些雇员的薪金高于Abel 的薪金? 使用子查询解决问题 假设要编写一个查询来找出谁的薪金高于Abel 的

oracle下session的查询与删除

oracle下session的查询与删除 1.查询当前session SQL> select username,sid,serial# from v$session where username is not null; USERNAME                              SID    SERIAL# ------------------------------ ---------- ---------- SYS