- 浏览: 41446 次
- 性别:
- 来自: 大连
最新评论
本篇文章详细介绍了Oracle的递归查询语法,利用此语法,可以方便地实现递归的双向查询:
一、测试准备
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);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (9,4 ,'1-2-4-9',3);
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来为每个层级的字段提供不同的缩进。
-----------------------------------------------------------------------------------------------------------
两个例子:
select 'perfuser'||level username,'perfuser'||level password from dual connect by level < 8;
select rownum cwh from dual connect by rownum < 6
-----------------------------------------------------------------------------------------------------------
一个实例:
1.树形结构如下:
a b
| |
c d
| |
e f
|
g
2.创建表,插入数据:
drop table tempone;
create table tempone
(name varchar2(8) primary key,
p_name varchar2(9),
num number
);
insert into tempone values ('a', '-1', 3);
insert into tempone values ('b', '-1', 4);
insert into tempone values ('c', 'a', 5 );
insert into tempone values ('d', 'b', 6 );
insert into tempone values ('e', 'c', 7 );
insert into tempone values ('f', 'd', 8 );
insert into tempone values ('g', 'e', 9 );
select * from tempone;
NAME P_NAME NUM
-------- --------- ----------
a -1 3
b -1 4
c a 5
d b 6
e c 7
f d 8
g e 9
3.需要获得如下结果:
NAME P_NAME NUM
-------- --------- ----------
a -1 24
b -1 18
其中24 = 3+5+7+9, 18 = 4+6+8
4.语句:
select name, p_name,
(select sum(num) from tempone connect by prior name = p_name start with name = a.name) num
from tempone a
where p_name = '-1'
为了加深理解,将where条件去掉,看看结果?
select name, p_name,
(select sum(num) from tempone connect by prior name = p_name start with name = a.name) num
from tempone a
再将Start with 去掉,看看结果?
select name, p_name,
(select sum(num) from tempone connect by prior name = p_name) num
from tempone a
发表评论
-
SQL Server 数据库备份
2015-11-25 10:31 548数据库备份与还原需要注意的地方: 1.在做数据库 ... -
SQL Server 2008 收缩日志 清空删除大日志文件
2015-11-24 16:50 732SQL2008 的收缩日志 由于SQL2008对文件和日志 ... -
字符串分组相加 row_number() 纵表转横表
2010-11-17 20:47 1650--1.准备工作create table TEST( id ... -
小技巧 自带函数、伪列
2010-11-15 20:07 923快速生成100条测试数据: create table ... -
oracle卸载步骤
2010-11-15 15:08 1014卸载oracle数据库的步骤如下:1、开始->设置->控制面板 ... -
Oracle数据库百分比格式化的解决方案
2010-08-10 13:42 1633对于不到1的数字,显示的类似于 .45样子的数据。0.45前面 ...
相关推荐
### Oracle数据库中的START WITH 和 CONNECT BY 用法详解 在Oracle数据库中,处理层次结构数据时,`START WITH` 和 `CONNECT BY` 是非常有用的两个关键字。这些关键字可以帮助我们在查询时构建出树形或者层级结构的...
### Oracle Start With.Connect By Prior 子句实现递归查询 #### 概述 在Oracle数据库中,`Start With.Connect By Prior`子句是执行递归查询的一种强大工具,主要用于处理层次结构数据。这类数据通常存在于组织...
ORACLE 查询树型关系(connect_by_prior_start_with) Oracle 查询树型关系是指使用 START WITH 和 CONNECT BY 子句来实现 SQL 的层次查询。从 Oracle 9i 开始,可以通过 SYS_CONNECT_BY_PATH 函数实现将父节点到...
本文章详细介绍了Oracle中connect by...start with...的用法。
### Oracle中的START WITH CONNECT BY PRIOR 用法详解 #### 一、概念介绍 在Oracle数据库中,`START WITH` 和 `CONNECT BY PRIOR` 是两个非常强大的特性,主要用于处理具有层级结构的数据。这两个特性可以帮助我们...
通常,`CONNECT BY`与`START WITH`一起使用,`START WITH`指定了层级遍历的起始节点。 例如,假设我们有一个员工表(EMPLOYEE),其中包含上级员工ID(MANAGER_ID)字段,我们可以使用以下查询来展示员工的管理层次...
`START WITH...CONNECT BY PRIOR`是Oracle SQL中的一个特性,用于处理具有层级关系的数据。这个子句允许我们遍历和查询具有父子关系的数据,例如部门和其下属子部门,或者员工和他们的上级经理。 1. **START WITH...
Oracle数据库通过提供`START WITH...CONNECT BY`语句来简化这类查询操作。此功能最早出现在Oracle 8.1.6版本,并一直沿用至今,成为处理递归查询的强大工具之一。 #### 二、Connect By与Start With详解 1. **...
connect by:connect by是必须的,start with有些情况是可以省略的,或者直接start with 1=1不加限制 prior:prior关键字可以放在等号的前面,也可以放在等号的后面,表示的意义是不一样的,比如 prior id = pid,...
Oracle 连接查询是指使用 START WITH 和 CONNECT BY 语句来实现递归查询的方法,这种方法可以生成树形结构的数据。在 Oracle 中,START WITH 语句用于指定递归查询的开始记录,而 CONNECT BY 语句用于指定递归查询的...
Connect By 可以列出上下级关系 构造序列 求排列组合 逆转求出下上级的关系路径
[ WHERE condition ][ [ START WITH condition ] CONNECT BY condition [ ORDER SIBLINGS BY expression ] ] ``` 其中,`START WITH`子句用于指定查询的起始节点,`CONNECT BY`子句用于指定查询的递归条件。 ...
with tt as ( select '0' as pid, '1' as id, '1' as name from dual union all select '1' as pid, '2' as id, '2' as name from dual union all select '1' as pid, '3' as id, '3' as name from dual union...
在SQL查询中,`START WITH` 和 `CONNECT BY` 是两个关键的子句,它们用于构建层次结构查询,通常在处理具有上下级关系的数据时非常有用,如员工与经理的关系、组织结构或者产品分类等。这两个子句是Oracle数据库特有...
Oracle是甲骨文公司的一款关系型...使用Connect By进行查询时,需要特别注意循环关系的处理,以及正确地使用`START WITH`、`CONNECT BY`子句和相关伪列。掌握这些知识点,对于Oracle数据库开发人员来说是必不可少的。
在Oracle数据库中,递归查询可以通过`START WITH CONNECT BY PRIOR`语句实现。此语句允许用户按照树状结构来检索数据。 ##### 1. `START WITH CONNECT BY PRIOR`用法详解 **基本语法**: ```sql SELECT * FROM ...
### Oracle中的Connect By Prior递归算法详解 ...通过正确地设置`START WITH`、`CONNECT BY`和`WHERE`子句,可以有效地查询和分析复杂的数据结构。理解其工作原理有助于更好地利用Oracle的功能来满足各种业务需求。
Oracle的`CONNECT BY`和分析函数是数据库查询中的两种强大工具,主要用于处理复杂的数据结构和进行高级数据分析。本文将深入探讨这两种技术。 ### Oracle `CONNECT BY` 用法总结 `CONNECT BY` 是Oracle SQL中用于...
递归树形结构查询主要依赖于`CONNECT BY`和`PRIOR`关键字,它们允许我们构建复杂的层级查询,以展示数据的层次关系。 在Oracle中,树形结构查询的基本语法如下: ```sql SELECT [LEVEL], * FROM table_name START ...