`

oracle递归查询

阅读更多
本文为CTRL+C\CTRL+V产物,在此感谢下作者^_^

Oracle 实在太强了,本篇文章详细介绍了Oracle的递归查询语法,利用此语法,可以方便地实现递归的双向查询:

  -- Tirle        : Recursion query for TREE with "connect by/start with"

  -- Author       : Rake Gao

  -- Create Date : 2005-08-22

  -- Version      : 2.0

  -- Last Modify : 2005-08-22

  目 录

  一、测试准备

  二、实现各种查询要求

  三、要点总结

  正 文

  一、测试准备

  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);

  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来为每个层级的字段提供不同的缩进。

分享到:
评论

相关推荐

    oracle递归查询的例子

    ### Oracle 递归查询详解及实例 #### 一、引言 在数据库查询语言中,Oracle 提供了一种强大的功能——递归查询,这在其他数据库系统如 SQL Server 中是缺失的功能。递归查询允许用户执行多级关联查询,特别适用于...

    oracle递归查询向上向下.txt

    oracle递归查询

    dhtmlx tree 使用,与oracle递归查询的结合

    综合以上信息,dhtmlx Tree结合Oracle递归查询提供了一种高效的方法来展示层次结构数据。通过优化数据库查询并减少应用程序中的计算负担,这种方法可以显著提升Web应用的性能。理解如何编写适当的SQL查询以及如何将...

    Oracle递归查询

    ### Oracle递归查询详解 #### 一、引言 在处理具有层级结构的数据时,递归查询是一项非常有用的技能。例如,在处理组织架构、产品分类等数据时,我们经常需要查询某一节点及其所有子节点或者从某个节点追溯到其根...

    oracle-递归查询地区名称

    oracle 递归调用 地区 ,用到的方法是 SYS_CONNECT_BY_PATH,可以扩展层级 名称

    oracle递归、迭代

    ### Oracle中的递归查询详解 #### 一、引言 在数据库管理中,处理具有层次结构的数据是一项常见的任务。例如,在组织结构、产品分类或文件系统等场景中,经常需要查询这种类型的层级数据。Oracle数据库提供了强大...

    Oracle递归树形结构查询功能

    Oracle数据库在处理树形结构数据时提供了强大的递归查询功能,这种特性对于组织结构、产品分类、层级菜单等场景的应用非常广泛。递归树形结构查询主要依赖于`CONNECT BY`和`PRIOR`关键字,它们允许我们构建复杂的...

    递归查询菜单树,支持mysql,oracle

    这里,我们将深入探讨如何使用递归查询来构建菜单树,并特别关注在MySQL和Oracle这两种广泛使用的数据库系统中的实现。 首先,我们要理解什么是递归查询。递归查询是一种在数据库中处理层次数据的方法,它通过自身...

    Oracle递归SQL学习

    这是Oracle递归查询的关键部分。`connect by`子句定义了层次之间的连接规则。在这里,`prior`关键字用来引用上一层的值,即父节点的`parent_id`应该等于当前行的`id`,这样我们就沿着父到子的方向遍历树。 3. `...

    深入sql oracle递归查询

    Oracle数据库系统提供了两种主要的递归查询方法:一种是使用`WITH`子句配合`UNION ALL`,另一种是使用`START WITH`和`CONNECT BY`。这两种方法都能解决查询层次关系的问题,例如找出某个节点的所有子节点或父节点。 ...

    递归查询父子关系记录 oracle

    oracle 如何递归查询父子关系。经常用于构造树结构

    Oracle 递归函数介绍

    在 Oracle 中,递归函数可以使用 CONNECT BY 语句来实现递归查询。CONNECT BY 语句的基本语法如下所示: ```sql SELECT ... FROM ... START WITH ... CONNECT BY ... ``` 其中,`START WITH` 子句指定了递归查询的...

    Oracle通过递归查询父子兄弟节点方法示例

    在Oracle数据库中,递归查询是一种强大的工具,用于处理层级数据结构,如组织结构、文件系统或树形关系。在本篇文章中,我们将探讨如何利用递归查询来查找父子兄弟节点,这对于理解和处理这类关系非常关键。 首先,...

    Oracle中的树状查询(递归查询)

    Oracle数据库系统在处理层次数据或树形结构时,提供了强大的工具——递归查询。递归查询允许我们在数据表中处理嵌套级别的数据,这在权限查询、组织结构、产品分类等场景中尤其常见。本文将深入探讨Oracle中的树状...

    数据库设计之递归树查询

    以下是在Oracle中进行递归查询的例子: ```sql SELECT id, name, CONNECT_BY_ROOT id AS root_id FROM employees START WITH id = some_employee_id CONNECT BY PRIOR id = manager_id; ``` 六、注意事项与优化 1....

    Oracle递归查询start with connect by prior的用法

    Oracle数据库中的递归查询是一种强大的工具,用于处理层次结构数据,如组织结构、产品分类或地理区域等。在Oracle中,`START WITH` 和 `CONNECT BY` 是进行递归查询的关键字,它们允许我们从一个特定的根节点出发,...

    在db2和oracle中的对树的递归查询语句

    在Oracle中,对树的递归查询主要依赖于`CONNECT_BY`功能。`CONNECT_BY`是Oracle SQL的一个扩展,用于处理层次查询。它允许我们通过指定的连接条件来遍历层级数据,从而进行递归查询。例如,我们可以用以下方式查询一...

    在ORACLE、MSSQL、MYSQL中树结构表递归查询的实现.pdf

    ORACLE、MSSQL(Microsoft SQL Server)、MYSQL是三大主流数据库系统,它们各自提供了不同的方式来实现递归查询。 首先,我们来看ORACLE数据库中的递归查询。ORACLE通过CONNECT BY子句来实现递归查询。CONNECT BY...

    MySQL递归查询

    MySQL 递归查询是指在 MySQL 中实现类似 Oracle Hierarchical Queries 的功能,用于查询树形结构中的所有子节点。由于 MySQL 目前还没有内置的递归查询功能,因此需要使用其他方法来实现。 第一种方法:使用函数来...

Global site tag (gtag.js) - Google Analytics