【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表

Oracle SqlServer Mysql 各自的 无限级 次数 递归 遍历树 结构记录数据 参考下面文章:

https://blog.csdn.net/xuheng8600/article/details/85848660

Oracle SqlServer Mysql 无限级 次数 递归 遍历树 Oracle start with...connect by prior, with as 递归 ,存储过程递归

 

先看Oracle官方文档:

https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Hierarchical-Queries.html#GUID-E3D35EF7-33C3-4D88-81B3-00030C47AE56

 

  1. Home
  2. Database
  3. Oracle
  4. Oracle Database
  5. Release 18

SQL Language Reference

 

Hierarchical Queries (SQL层次查询)

If a table contains hierarchical data, then you can select rows in a hierarchical order using the hierarchical query clause:

hierarchical_query_clause::=

Description of hierarchical_query_clause.eps follows
Description of the illustration hierarchical_query_clause.eps

condition can be any condition as described in Conditions.

START WITH specifies the root row(s) of the hierarchy.

CONNECT BY specifies the relationship between parent rows and child rows of the hierarchy.

  • The NOCYCLE parameter instructs Oracle Database to return rows from a query even if a CONNECT BY loop exists in the data. Use this parameter along with the CONNECT_BY_ISCYCLE pseudocolumn to see which rows contain the loop. Refer to CONNECT_BY_ISCYCLE Pseudocolumn for more information.

  • In a hierarchical query, one expression in condition must be qualified with the PRIOR operator to refer to the parent row. For example,

    ... PRIOR expr = expr
    or
    ... expr = PRIOR expr
    

    If the CONNECT BY condition is compound, then only one condition requires the PRIOR operator, although you can have multiple PRIOR conditions. For example:

    CONNECT BY last_name != 'King' AND PRIOR employee_id = manager_id ...
    CONNECT BY PRIOR employee_id = manager_id and 
               PRIOR account_mgr_id = customer_id ...
    

    PRIOR is a unary operator and has the same precedence as the unary + and - arithmetic operators. It evaluates the immediately following expression for the parent row of the current row in a hierarchical query.

    PRIOR is most commonly used when comparing column values with the equality operator. (The PRIOR keyword can be on either side of the operator.) PRIOR causes Oracle to use the value of the parent row in the column. Operators other than the equal sign (=) are theoretically possible in CONNECT BY clauses. However, the conditions created by these other operators can result in an infinite loop through the possible combinations. In this case Oracle detects the loop at run time and returns an error.

Both the CONNECT BY condition and the PRIOR expression can take the form of an uncorrelated subquery. However, CURRVAL and NEXTVAL are not valid PRIOR expressions, so the PRIOR expression cannot refer to a sequence.

You can further refine a hierarchical query by using the CONNECT_BY_ROOT operator to qualify a column in the select list. This operator extends the functionality of the CONNECT BY [PRIOR] condition of hierarchical queries by returning not only the immediate parent row but all ancestor rows in the hierarchy.

See Also:

CONNECT_BY_ROOT for more information about this operator and "Hierarchical Query Examples"

Oracle processes hierarchical queries as follows:

  • A join, if present, is evaluated first, whether the join is specified in the FROM clause or with WHERE clause predicates.

  • The CONNECT BY condition is evaluated.

  • Any remaining WHERE clause predicates are evaluated.

Oracle then uses the information from these evaluations to form the hierarchy using the following steps:

  1. Oracle selects the root row(s) of the hierarchy—those rows that satisfy the START WITH condition.

  2. Oracle selects the child rows of each root row. Each child row must satisfy the condition of the CONNECT BY condition with respect to one of the root rows.

  3. Oracle selects successive generations of child rows. Oracle first selects the children of the rows returned in step 2, and then the children of those children, and so on. Oracle always selects children by evaluating the CONNECT BY condition with respect to a current parent row.

  4. If the query contains a WHERE clause without a join, then Oracle eliminates all rows from the hierarchy that do not satisfy the condition of the WHERE clause. Oracle evaluates this condition for each row individually, rather than removing all the children of a row that does not satisfy the condition.

  5. Oracle returns the rows in the order shown in Figure 9-1. In the diagram, children appear below their parents. For an explanation of hierarchical trees, see Figure 3-1.

Figure 9-1 Hierarchical Queries

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第1张图片
Description of "Figure 9-1 Hierarchical Queries"

To find the children of a parent row, Oracle evaluates the PRIOR expression of the CONNECT BY condition for the parent row and the other expression for each row in the table. Rows for which the condition is true are the children of the parent. The CONNECT BYcondition can contain other conditions to further filter the rows selected by the query.

If the CONNECT BY condition results in a loop in the hierarchy, then Oracle returns an error. A loop occurs if one row is both the parent (or grandparent or direct ancestor) and a child (or a grandchild or a direct descendent) of another row.

Note:

In a hierarchical query, do not specify either ORDER BY or GROUP BY, as they will override 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.

Hierarchical Query Examples

CONNECT BY Example

The following hierarchical query uses the CONNECT BY clause to define the relationship between employees and managers:

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

EMPLOYEE_ID LAST_NAME                 MANAGER_ID
----------- ------------------------- ----------
        101 Kochhar                          100
        108 Greenberg                        101
        109 Faviet                           108
        110 Chen                             108
        111 Sciarra                          108
        112 Urman                            108
        113 Popp                             108
        200 Whalen                           101
        203 Mavris                           101
        204 Baer                             101
. . .

LEVEL Example

The next example is similar to the preceding example, but uses the LEVEL pseudocolumn to show parent and child rows:

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

EMPLOYEE_ID LAST_NAME                 MANAGER_ID      LEVEL
----------- ------------------------- ---------- ----------
        101 Kochhar                          100          1
        108 Greenberg                        101          2
        109 Faviet                           108          3
        110 Chen                             108          3
        111 Sciarra                          108          3
        112 Urman                            108          3
        113 Popp                             108          3
        200 Whalen                           101          2
        203 Mavris                           101          2
        204 Baer                             101          2
        205 Higgins                          101          2
        206 Gietz                            205          3
        102 De Haan                          100          1
...

START WITH Examples

The next example adds a START WITH clause to specify a root row for the hierarchy and an ORDER BY clause using the SIBLINGSkeyword to preserve ordering within the hierarchy:

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
...

In the hr.employees table, the employee Steven King is the head of the company and has no manager. Among his employees is John Russell, who is the manager of department 80. If you update the employees table to set Russell as King's manager, you create a loop in the data:

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;

ERROR:
ORA-01436: CONNECT BY loop in user data

The NOCYCLE parameter in the CONNECT BY condition causes Oracle to return the rows in spite of the loop. The CONNECT_BY_ISCYCLE pseudocolumn shows you which rows contain the cycle:

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

Employee                       Cycle      LEVEL Path
------------------------- ---------- ---------- -------------------------
Abel                               0          3 /King/Zlotkey/Abel
Ande                               0          3 /King/Errazuriz/Ande
Banda                              0          3 /King/Errazuriz/Banda
Bates                              0          3 /King/Cambrault/Bates
Bernstein                          0          3 /King/Russell/Bernstein
Bloom                              0          3 /King/Cambrault/Bloom
Cambrault                          0          2 /King/Cambrault
Cambrault                          0          3 /King/Russell/Cambrault
Doran                              0          3 /King/Partners/Doran
Errazuriz                          0          2 /King/Errazuriz
Fox                                0          3 /King/Cambrault/Fox
...

CONNECT_BY_ISLEAF Example

The following statement shows how you can use a hierarchical query to turn the values in a column into a comma-delimited list:

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; 
 
LTRIM(SYS_CONNECT_BY_PATH(WAREHOUSE_ID,','),',')
--------------------------------------------------------------------------------
1,2,3,4,5,6,7,8,9

CONNECT_BY_ROOT Examples

The following example returns the last name of each employee in department 110, each manager at the highest level above that employee in the hierarchy, the number of levels between manager and employee, and the path between the two:

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

Employee        Manager            Pathlen Path
--------------- --------------- ---------- ------------------------------
Gietz           Higgins                  1 /Higgins/Gietz
Gietz           King                     3 /King/Kochhar/Higgins/Gietz
Gietz           Kochhar                  2 /Kochhar/Higgins/Gietz
Higgins         King                     2 /King/Kochhar/Higgins
Higgins         Kochhar                  1 /Kochhar/Higgins

The following example uses a GROUP BY clause to return the total salary of each employee in department 110 and all employees above that employee in the hierarchy:

SELECT name, SUM(salary) "Total_Salary" FROM (
   SELECT CONNECT_BY_ROOT last_name as name, Salary
      FROM employees
      WHERE department_id = 110
      CONNECT BY PRIOR employee_id = manager_id)
      GROUP BY name
   ORDER BY name, "Total_Salary";

NAME                      Total_Salary
------------------------- ------------
Gietz                             8300
Higgins                          20300
King                             20300
Kochhar                          20300

 

See Also:

  • LEVEL Pseudocolumn and CONNECT_BY_ISCYCLE Pseudocolumn for a discussion of how these pseudocolumns operate in a hierarchical query

  • SYS_CONNECT_BY_PATH for information on retrieving the path of column values from root to node

  • order_by_clause for more information on the SIBLINGS keyword of ORDER BY clauses

  • subquery_factoring_clause, which supports recursive subquery factoring (recursive WITH) and lets you query hierarchical data. This feature is more powerful than CONNECT BY in that it provides depth-first search and breadth-first search, and supports multiple recursive branches.

  • Previous
  • Next

https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Hierarchical-Queries.html#GUID-E3D35EF7-33C3-4D88-81B3-00030C47AE56

 

 

 

 

 

 

 

https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Hierarchical-Query-Pseudocolumns.html#GUID-D91FFF59-ECB0-40F0-AB4C-7A9D27EBEEF1

Hierarchical Query Pseudocolumns (层次查询伪列)

The hierarchical query pseudocolumns are valid only in hierarchical queries. The hierarchical query pseudocolumns are:

  • CONNECT_BY_ISCYCLE Pseudocolumn

  • CONNECT_BY_ISLEAF Pseudocolumn

  • LEVEL Pseudocolumn

To define a hierarchical relationship in a query, you must use the CONNECT BY clause.

CONNECT_BY_ISCYCLE Pseudocolumn

The CONNECT_BY_ISCYCLE pseudocolumn returns 1 if the current row has a child which is also its ancestor. Otherwise it returns 0.

You can specify CONNECT_BY_ISCYCLE only if you have specified the NOCYCLE parameter of the CONNECT BY clause. NOCYCLE enables Oracle to return the results of a query that would otherwise fail because of a CONNECT BY loop in the data.

See Also:

Hierarchical Queries for more information about the NOCYCLE parameter and Hierarchical Query Examples for an example that uses the CONNECT_BY_ISCYCLE pseudocolumn

CONNECT_BY_ISLEAF Pseudocolumn

The CONNECT_BY_ISLEAF pseudocolumn returns 1 if the current row is a leaf of the tree defined by the CONNECT BY condition. Otherwise it returns 0. This information indicates whether a given row can be further expanded to show more of the hierarchy.

CONNECT_BY_ISLEAF Example

The following example shows the first three levels of the hr.employees table, indicating for each row whether it is a leaf row (indicated by 1 in the IsLeaf column) or whether it has child rows (indicated by 0 in the IsLeaf column):

SELECT last_name "Employee", CONNECT_BY_ISLEAF "IsLeaf",
       LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path"
  FROM employees
  WHERE LEVEL <= 3 AND department_id = 80
  START WITH employee_id = 100
  CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 4
  ORDER BY "Employee", "IsLeaf";

Employee                      IsLeaf      LEVEL Path
------------------------- ---------- ---------- -------------------------
Abel                               1          3 /King/Zlotkey/Abel
Ande                               1          3 /King/Errazuriz/Ande
Banda                              1          3 /King/Errazuriz/Banda
Bates                              1          3 /King/Cambrault/Bates
Bernstein                          1          3 /King/Russell/Bernstein
Bloom                              1          3 /King/Cambrault/Bloom
Cambrault                          0          2 /King/Cambrault
Cambrault                          1          3 /King/Russell/Cambrault
Doran                              1          3 /King/Partners/Doran
Errazuriz                          0          2 /King/Errazuriz
Fox                                1          3 /King/Cambrault/Fox
. . . 

See Also:

Hierarchical Queries and SYS_CONNECT_BY_PATH

LEVEL Pseudocolumn

For each row returned by a hierarchical query, the LEVEL pseudocolumn returns 1 for a root row, 2 for a child of a root, and so on. A root row is the highest row within an inverted tree. A child row is any nonroot row. A parent row is any row that has children. A leaf row is any row without children. Figure 3-1 shows the nodes of an inverted tree with their LEVEL values.

Figure 3-1 Hierarchical Tree

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第2张图片
Description of "Figure 3-1 Hierarchical Tree "

See Also:

Hierarchical Queries for information on hierarchical queries in general and IN Condition for restrictions on using the LEVELpseudocolumn

  • Previous
  • Next

https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Hierarchical-Query-Pseudocolumns.html#GUID-D91FFF59-ECB0-40F0-AB4C-7A9D27EBEEF1

 

 

 

 

 

 

 

https://blog.csdn.net/u013766398/article/details/53285327

Oracle start with connect by prior 用法(递归查询树形结构)

2016年11月22日 14:13:18 风灵寒 阅读数:461

语法:

select * from  表名 where  条件1 start with 条件2 connect by prior 当前表字段=级联表字段。

start with与connect by prior语句完成递归记录,形成一棵树形结构,通常可以在具有层次结构的表中使用。

start with:表示开始的记录

connect by prior:指定与当前记录关联时的字段关系

 代码:--

创建部门表,这是一个具有层次结构的表,子记录通过parent_id与父记录的id进行关联

create table DEPT( 

ID NUMBER(9) PRIMARY KEY       --部门ID 

NAME VARCHAR2(100),             --部门名称

PARENT_ID NUMBER(9) --父级部门ID,通过此字段与上级部门关联

); 

向表中插入如下数据,为了使代码简单,一个部门仅具有一个下级部门

从根节点开始查询递归的记录

select * from dept  start with id=1 connect by prior id = parent_id; 

下面是查询结果,

start with id=1  表示从id=1的记录开始查询,向叶子的方向递归,递归条件是id=parent_id,当前记录的id等于子记录的parent_id 

●从叶子节点开始查询递归的记录

 select * from dept start with id=5 connect by prior parent_id = id; 

下面是查询结果,递归条件按照当前记录的parent_id等与父记录的id 

●对查询结果过滤

select * from dept where name like '%销售%' start with id=1 connect by prior id = parent_id;

在下面的查询结果中可以看到,首先使用start with... connect by prior查询出树形的结构,然后where条件才生效,对全部查询结果进行过滤

●prior的作用

 prior关键字表示不进行递归查询,仅查询出满足id=1的记录,下面是将第一个查询去掉prior关键字后结果

select * from dept start with id=1 connect by prior id = parent_id

注:select connect_by_root 列名  from 表名 where条件1 start with 条件2 connect by prior 当前表字段=级联表字段。

表示查找父级(父亲)的直系子级(儿子)

http://blog.csdn.net/u013492963/article/details/18551701

https://blog.csdn.net/u013766398/article/details/53285327

 

 

 

 

 

 

 

https://blog.csdn.net/feier7501/article/details/21815691

oracle 递归查询 CONNECT BY、START WITH、CONNECT_BY_ROOT、CONNECT_BY_ISLEAF、SYS_CONNECT_BY_PATH

2014年03月22日 18:21:37 feier7501 阅读数:5985更多

个人分类: oracle

创建表,初始化数据;

 

 
  1. CREATE TABLE TB_COMPANY

  2. (

  3. COMPANY_ID INTEGER PRIMARY KEY,

  4. COMPANY VARCHAR2(256),

  5. UP_COMPANYID INTEGER

  6. );

  7.  
  8. INSERT INTO TB_COMPANY VALUES (0, '总公司', NULL);

  9. INSERT INTO TB_COMPANY VALUES (1, '北京分公司', 0);

  10. INSERT INTO TB_COMPANY VALUES (2, '上海分公司', 0);

  11. INSERT INTO TB_COMPANY VALUES (3, '海淀区分部', 1);

  12. INSERT INTO TB_COMPANY VALUES (4, '东城区分部', 1);

  13. INSERT INTO TB_COMPANY VALUES (5, '黄埔区分部', 2);

  14. INSERT INTO TB_COMPANY VALUES (6, '静安区分部', 2);

  15. COMMIT;


全部数据:

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第3张图片

 

递归查询SQL:

 

 
  1. SELECT (RPAD(' ', 2*(LEVEL-1), '-' ) || COMPANY) COMPANY_NAME, CONNECT_BY_ROOT COMPANY, CONNECT_BY_ISLEAF, LEVEL , SYS_CONNECT_BY_PATH(COMPANY, '/')

  2. FROM TB_COMPANY

  3. START WITH UP_COMPANYID IS NULL

  4. CONNECT BY PRIOR COMPANY_ID = UP_COMPANYID;


结果:

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第4张图片

 

说明:

1. CONNECT_BY_ROOT 返回当前节点的最顶端节点 
2. CONNECT_BY_ISLEAF 判断是否为叶子节点,如果这个节点下面有子节点,则不为叶子节点 
3. LEVEL 伪列表示节点深度 
4. SYS_CONNECT_BY_PATH函数显示详细路径,并用“/”分隔

 

递归查询SQL:

 

SELECT * FROM TB_COMPANY START WITH COMPANY_ID = 1 CONNECT BY PRIOR COMPANY_ID = UP_COMPANYID;


结果:

 收藏 

 分享

https://blog.csdn.net/feier7501/article/details/21815691

 

 

 

 

 

 

 

https://blog.csdn.net/guaoran/article/details/52918372

利用start with connect by 查询子节点和父节点数据显示为树状形

2016年10月25日 09:27:11 guaoran 阅读数:2322 标签: Oracle使用sql查询出树状型根据子节点和父节点查询出树状型start with connect b 更多

个人分类: oracle

利用start with   connect by  查询子节点和父节点数据显示为树状形

 

前段时间做了一个根据子节点和父节点查询出树状型

表数据:

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第5张图片

要实现的结果:

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第6张图片

 

实现的sql:

 
  1. select rpad('---', (level - 1) * 3, '---') || name as name, id

  2. from t_nscreen_region

  3. start with id = 1

  4. connect by nocycle prior id = parent_id

order SIBLINGS BY id;

 

 

 

其中函数理解:

1.PRIOR 
   阶层查询的CONNECY BY condition的条件式需要用到PRIOR来指定父节点
2.CONNECT BY
   通过CONNECT BY子句定义子节点和父节点的关系
3.start with 
   通过start with 指定根节点(不指定start with会出现重复记,不指定NOCYCLE没事)
4.LEVEL 
   通过LEVEL虚拟列表示节点的关系
5.rpad(string,padded_length,[pad_string])函数
   从右边对字符串使用指定的字符进行填充
   string:表示要追加的字符,
   padded_length:表示追加后的长度
   pad_string:表示string字符长度不够padded_length时,取pad_string的字符,默认为空格

6.lpad( string1, padded_length, [ pad_string ] )函数
   从左边对字符串使用指定的字符进行填充
   string1:源字符串
   padded_length:最终返回的字符串的长度,如果最终返回的字符串的长度比源字符串的小,那么此函数实际上对源串进行截断处理
   pad_string:用于填充的字符,可以不填,默认为空字符
7.order SIBLINGS BY id :按id进行排序

 

 收藏 

 分享

https://blog.csdn.net/guaoran/article/details/52918372

 

 

 

 

 

 

 

https://zhidao.baidu.com/question/752780874722290124.html

oracle 递归查询 能限定递归次数么

 

oracle递归查询
Oracle中start by prior子句用法
connect by 是结构化查询中用到的,其基本语法是:
select ... from tablename start with 条件1
connect by 条件2
where 条件3;

例:
select * from table
start with org_id = 'HBHqfWGWPy'
connect by prior org_id = parent_id;

简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段:
org_id,parent_id那么通过表示每一条记录的parent是谁,就可以形成一个树状结构。
用上述语法的查询可以取得这棵树的所有记录。
其中:

条件1 是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。
条件2 是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR org_id = parent_id就是说上一条记录的org_id 是本条记录的parent_id,即本记录的父亲是上一条记录。
条件3 是过滤条件,用于对返回的所有记录进行过滤。

简单介绍如下:

早扫描树结构表时,需要依此访问树结构的每个节点,一个节点只能访问一次,其访问的步骤如下:
第一步:从根节点开始;
第二步:访问该节点;
第三步:判断该节点有无未被访问的子节点,若有,则转向它最左侧的未被访问的子节,并执行第二步,否则执行第四步;
第四步:若该节点为根节点,则访问完毕,否则执行第五步;
第五步:返回到该节点的父节点,并执行第三步骤。

总之:扫描整个树结构的过程也即是中序遍历树的过程。

1. 树结构的描述
树结构的数据存放在表中,数据之间的层次关系即父子关系,通过表中的列与列间的关系来描述,如EMP表中的EMPNO和MGR。EMPNO表示该雇员的编号,MGR表示领导该雇员的人的编号,即子节点的MGR值等于父节点的EMPNO值。在表的每一行中都有一个表示父节点的MGR(除根节点外),通过每个节点的父节点,就可以确定整个树结构。
在SELECT命令中使用CONNECT BY 和蔼START WITH 子句可以查询表中的树型结构关系。其命令格式如下:
SELECT 。。。
CONNECT BY {PRIOR 列名1=列名2|列名1=PRIOR 裂名2}
[START WITH];
其中:CONNECT BY子句说明每行数据将是按层次顺序检索,并规定将表中的数据连入树型结构的关系中。PRIORY运算符必须放置在连接关系的两列中某一个的前面。对于节点间的父子关系,PRIOR运算符在一侧表示父节点,在另一侧表示子节点,从而确定查找树结构是的顺序是自顶向下还是自底向上。在连接关系中,除了可以使用列名外,还允许使用列表达式。START WITH 子句为可选项,用来标识哪个节点作为查找树型结构的根节点。若该子句被省略,则表示所有满足查询条件的行作为根节点。

START WITH: 不但可以指定一个根节点,还可以指定多个根节点。
2. 关于PRIOR
运算符PRIOR被放置于等号前后的位置,决定着查询时的检索顺序。
PRIOR被置于CONNECT BY子句中等号的前面时,则强制从根节点到叶节点的顺序检索,即由父节点向子节点方向通过树结构,我们称之为自顶向下的方式。如:
CONNECT BY PRIOR EMPNO=MGR
PIROR运算符被置于CONNECT BY 子句中等号的后面时,则强制从叶节点到根节点的顺序检索,即由子节点向父节点方向通过树结构,我们称之为自底向上的方式。例如:
CONNECT BY EMPNO=PRIOR MGR
在这种方式中也应指定一个开始的节点。
3. 定义查找起始节点
在自顶向下查询树结构时,不但可以从根节点开始,还可以定义任何节点为起始节点,以此开始向下查找。这样查找的结果就是以该节点为开始的结构树的一枝。

4.使用LEVEL
在具有树结构的表中,每一行数据都是树结构中的一个节点,由于节点所处的层次位置不同,所以每行记录都可以有一个层号。层号根据节点与根节点的距离确定。不论从哪个节点开始,该起始根节点的层号始终为1,根节点的子节点为2, 依此类推。图1.2就表示了树结构的层次。

5.节点和分支的裁剪
在对树结构进行查询时,可以去掉表中的某些行,也可以剪掉树中的一个分支,使用WHERE子句来限定树型结构中的单个节点,以去掉树中的单个节点,但它却不影响其后代节点(自顶向下检索时)或前辈节点(自底向顶检索时)。
6.排序显示
象在其它查询中一样,在树结构查询中也可以使用ORDER BY 子句,改变查询结果的显示顺序,而不必按照遍历树结构的顺序。

 本回答由提问者推荐

https://zhidao.baidu.com/question/752780874722290124.html

 

 

 

 

 

Debugs

 

随笔 - 152  文章 - 1  评论 - 0

oracle的递归运算(树运算) 无限树形

 

oracle的递归运算(树运算)start with org_id ='1'connect by prior parent_id=son_id

 
1.前言 
  oracle的递归运算,在我们web页面的目录结构中会经常用到,据说是面试经常出的题目,而网上的一些东西说得都不是很明了,所以自己整理了一下,以下主要通过一个例子来说明,可以直接copy代码运行一下。 
  www.2cto.com  
2.start with org_id = '条件1'  prior parent_id =  son_id; 的作用 
  这个就是为了把树形结构全部查出来,树的目录就放在同一张表中,如 

|--2 
|--3 
|--4 
   |--5 
      |--6 
|--7 
   |--8 
      |--9 
         |--10 
  www.2cto.com  
这样的结构怎么查出来呢,这种特殊的查询,connect by perior就派上用场了 。 
3.代码 
Java代码  
create table TESTTEMP  
(  
  parent_ID    VARCHAR2(30),  
  son_ID VARCHAR2(30)  
);  
  
insert into TESTTEMP values('1','0');  
insert into TESTTEMP values('1','2');  
insert into TESTTEMP values('1','3');  
insert into TESTTEMP values('1','4');  
insert into TESTTEMP values('1','7');  
insert into TESTTEMP values('4','5');  
insert into TESTTEMP values('5','6');  
insert into TESTTEMP values('7','8');  
insert into TESTTEMP values('8','9');  
insert into TESTTEMP values('9','10');  
commit;  
select * from TESTTEMP   
start with parent_ID='1'  
connect  by  parent_ID= prior son_ID   
  www.2cto.com  
结果: 
1 0 
1 2 
1 3 
1 4 
4 5 
5 6 
1 7 
7 8 
8 9 
9 10 
4。总结 
  上面的例子,作用是实现遍历所有节点。如果prior 放在 connect  by后面的话,那就是从上查找

 

 

 

 

 

分类: Oracle

好文要顶 关注我 收藏该文  

Debugs
关注 - 0
粉丝 - 0

+加关注

0

0

« 上一篇:oracle递归查询子节点
» 下一篇:使用jQuery.noConflict方法来轻松实现控制权的转交

posted @ 2017-08-22 12:40 Debugs 阅读(372) 评论(0) 编辑 收藏

刷新评论刷新页面返回顶部

 

https://www.cnblogs.com/yangpeng-jingjing/p/7411037.html

 

 

 

 

 

 

https://blog.csdn.net/jackpk/article/details/3247549

oracle中进行简单树查询(递归查询) ,PRIOR、CONNECT_BY_ROOT的使用

2008年11月07日 16:05:00 jackpk 阅读数:11211 标签: oraclemanagerpathupuser数据库 更多

个人分类: oracle

 

select AD_DEPARTMENT_CODE, AD_DEPARTMENT_UP_LEVEL, AD_DEPARTMENT_NAME

  from (select AD_DEPARTMENT_CODE,

               AD_DEPARTMENT_UP_LEVEL,

               AD_DEPARTMENT_NAME

          from AD_DEPT_ARCHITECTURE

         order by AD_DEPARTMENT_UP_LEVEL, AD_DEPARTMENT_CODE)

 start with AD_DEPARTMENT_CODE = '0'

connect by prior AD_DEPARTMENT_CODE = AD_DEPARTMENT_UP_LEVEL;

from 后边 select 结果集合进行了排序,然后,start with connect by prior这些语句起了作用,按照刚才查询出来结果集的顺序,

(1)       先找到AD_DEPARTMENT_CODE = '0'的作为第一条记录(A),将其加入到要构建的树状结构中。

(2)       然后顺序从排完序的结果集中找出,第一条记录的头一个子结点(B)添加到树中。如第一个子结点还有它的子结点,就依次从刚才的查询出来的结果集中找到B的子节点C1C2C3。。。依次添加到树中。

(3)       。。。。

 有了from 后的select结果集的排序,得到的树状结构更加有序。

 

  • 生成媒体频道栏目父子关系树状关系

SELECT APR_CODE, APR_CODE_UP, NAMES

  FROM (SELECT A.MEDIA_CODE || '|' || A.CHANNEL_CODE || '|' || A.COLUMN_CODE AS APR_CODE,

               A.MEDIA_CODE_UP || '|' || A.CHANNEL_CODE_UP || '|' ||

               A.COLUMN_CODE_UP AS APR_CODE_UP,

               DECODE((B.MEDIA_NAME || '-' || C.CHANNEL_CODE || '-' ||

                      D.COLUMN_NAME),

                      '--',

                      '产品关系',

                      (B.MEDIA_NAME || '|' || C.CHANNEL_CODE || '|' ||

                      D.COLUMN_NAME)) NAMES

          FROM COLUMNS D, CHANNEL C, MEDIA B, AD_PRODUCT_RELATION A

         WHERE A.MEDIA_CODE = B.MEDIA_CODE(+)

           AND A.MEDIA_CODE = C.MEDIA_CODE(+)

           AND A.CHANNEL_CODE = C.CHANNEL_CODE(+)

           AND A.MEDIA_CODE = D.MEDIA_CODE(+)

           AND A.CHANNEL_CODE = D.CHANNEL_CODE(+)

           AND A.COLUMN_CODE = D.COLUMN_CODE(+))

 START WITH APR_CODE = '0|0|0'

CONNECT BY PRIOR APR_CODE = APR_CODE_UP

 

这里利用'-' '|'来进行区分,找出了树状结构的根

为了构建树,

1)先建立了树结构的根,字段这里都设为“0”或者“00

2)然后再根据需要填充数据

3)利用上边的oracle PRIORCONNECT_BY_ROOT 等进行层次查询

 

 

  • 递归查询时:由于数据类型不正确而导致ORA-01436: CONNECT BY loop in user data

错误原因:在数据库表TRASFER中,TRASFER字段为number类型,而TAPE_NO字段为Varchar2类型。由于在进行父子关系判定中“TRANSFER = TAPE_NO”两者的字段类型不同而导致:ORA-01436

 

正确语句:

SELECT TRANSFER, TAPE_NO, TRANSFER_NAME

  FROM (SELECT TRANSFER, TAPE_NO, TRANSFER_NAME

          FROM TRANSFER

         ORDER BY TAPE_NO, TRANSFER)

 START WITH TRANSFER = 0

CONNECT BY PRIOR TO_CHAR(TRANSFER) = TAPE_NO

 

 

 

参考一

PL/SQL基础:阶层查询

作者:itpub cxck  2007-05-08

内容导航:

 ORACLE 10g新增了阶层查询操作符PRIORCONNECT_BY_ROOT 

PRIOR 
阶层查询的CONNECY BY condition的条件式需要用到PRIOR来指定父节点,
 
作为运算符,PRIOR和加(+)(-)运算的优先级相同。
 

■阶层查询
 
语法:START WITH
 condition CONNECT BY NOCYCLE condition 

START WITH 
指定阶层的根 

CONNECT BY 指定阶层的父/子关系 
NOCYCLE 存在CONNECT BY LOOP的纪录时,也返回查询结果。 
condition ... PRIOR expr = expr 
或者
 ... expr = PRIOR expr 
例:
 
CONNECT BY last_name != 'King' AND PRIOR employee_id = manager_id ... 
CONNECT BY PRIOR employee_id = manager_id and 
PRIOR account_mgr_id = customer_id ... 


CONNECT_BY_ROOT 
查询指定根的阶层数据。
 

CONNECT BY子句的例子
 
通过CONNECT BY子句定义职员和上司的关系。
 
SQL>SELECT employee_id, last_name, manager_id 
FROM employees 
CONNECT BY PRIOR employee_id = manager_id; 

EMPLOYEE_ID LAST_NAME MANAGER_ID 
----------- ------------------------- ---------- 
101 Kochhar 100 
108 Greenberg 101 
109 Faviet 108 
110 Chen 108 
111 Sciarra 108 
112 Urman 108 
113 Popp 108 
200 Whalen 101 


LEVEL的例子
 
通过LEVEL虚拟列表示节点的关系。
 
SQL>SELECT employee_id, last_name, manager_id, LEVEL 
FROM employees 
CONNECT BY PRIOR employee_id = manager_id; 

EMPLOYEE_ID LAST_NAME MANAGER_ID LEVEL 
----------- ------------------------- ---------- ---------- 
101 Kochhar 100 1 
108 Greenberg 101 2 
109 Faviet 108 3 
110 Chen 108 3 
111 Sciarra 108 3 
112 Urman 108 3 
113 Popp 108 3 


START WITH子句的例子
 
通过START WITH指定根节点,ORDER SIBLINGS BY保持阶层的顺序。

SQL>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

 


hr.employees里,Steven King是公司的最高责任者,没有上司,他有一个叫John Russell的下属是部门80的管理者。 
更新employees表,把Russell设置成King的上司,这样就产生了CONNECT BY LOOP

SQL>UPDATE employees SET manager_id = 145

WHERE employee_id = 100;

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

2 3 4 5 6 7 ERROR:

ORA-01436: CONNECT BY loop in user data

CONNECT BY NOCYCLE强制返回查询结果。CONNECT_BY_ISCYCLE显示是否存在LOOP

SQL>SELECT last_name "Employee", CONNECT_BY_ISCYCLE "Cycle",

LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path"

FROM employees

WHERE level <= 3 AND department_id = 80

START WITH last_name = 'King'

CONNECT BY NOCYCLE PRIOR employee_id = manager_id AND LEVEL <= 4;

Employee Cycle LEVEL Path

------------------------- ------ ------ -------------------------

Russell 1 2 /King/Russell

Tucker 0 3 /King/Russell/Tucker

Bernstein 0 3 /King/Russell/Bernstein

Hall 0 3 /King/Russell/Hall

Olsen 0 3 /King/Russell/Olsen

Cambrault 0 3 /King/Russell/Cambrault

Tuvault 0 3 /King/Russell/Tuvault

Partners 0 2 /King/Partners

King 0 3 /King/Partners/King

Sully 0 3 /King/Partners/Sully

McEwen 0 3 /King/Partners/McEwen

 


CONNECT_BY_ROOT的例子 
1
,查询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;

Employee Manager Pathlen Path

--------------- ------------ ---------- -----------------------------------

Higgins Kochhar 1 /Kochhar/Higgins

Gietz Kochhar 2 /Kochhar/Higgins/Gietz

Gietz Higgins 1 /Higgins/Gietz

Higgins King 2 /King/Kochhar/Higgins

Gietz King 3 /King/Kochhar/Higgins/Gietz

 



2,使用GROUP BY语句,查询110部门的职员以及该职员下属职员的工资和。

SELECT name, SUM(salary) "Total_Salary" FROM (

SELECT CONNECT_BY_ROOT last_name as name, Salary

FROM employees

WHERE department_id = 110

CONNECT BY PRIOR employee_id = manager_id)

GROUP BY name;

NAME Total_Salary

------------------------- ------------

Gietz 8300

Higgins 20300

King 20300

Kochhar 20300

 

 

 

 

参考二

对于oracle进行简单树查询(递归查询)

DEPTID

PAREDEPTID

NAME

NUMBER

NUMBER

CHAR (40 Byte)

部门id

父部门id(所属部门id)

部门名称

 

通过子节点向根节点追朔.
select * from persons.dept start with deptid=76 connect by prior paredeptid=deptid
通过根节点遍历子节点.
select * from persons.dept start with paredeptid=0 connect by prior deptid=paredeptid
可通过level 关键字查询所在层次.
select a.*,level from persons.dept a start with paredeptid=0 connect by prior deptid=paredeptid
再次复习一下:start with ...connect by 的用法, start with 后面所跟的就是就是递归的种子
递归的种子也就是递归开始的地方
connect by 后面的"prior" 如果缺省:则只能查询到符合条件的起始行,并不进行递归查询;
connect by prior 后面所放的字段是有关系的,它指明了查询的方向。

对于prior我是这样理解的:

上边例子中,比如:“prior deptid = paredeptid”,意思是:祖先(上一层记录)的deptid等于本条记录的paredeptid,即:通过根节点遍历子节点


练习: 通过子节点获得顶节点
select FIRST_VALUE(deptid)
  OVER (ORDER BY LEVEL DESC ROWS UNBOUNDED PRECEDING) AS firstdeptid from  persons.dept   start with deptid=76 connect by prior paredeptid=deptid

 

https://blog.csdn.net/jackpk/article/details/3247549

 

 

 

 

 

 

https://blog.csdn.net/m0_37298602/article/details/77472942

Oracle 层次查询(递归查询)(level start with connect by prior)

2017年08月22日 10:03:14 King_Kwin 阅读数:578

 

声明:部分内容来源于网络资源,只为记录学习使用,如有侵权,请留言删除

层次查询的概念

语法格式:

select [level], column, expr... from table
[where condition]
start with condition
connect by [prior column1= column2 |
column1 = prior column2];

层次查询是通过start with和connect by子句标识的:

1.其中level关键字是可选的,表示等级,1表示root,2表示root的child,其他相同的规则。

2.From之后可以是table,view但是只能是一个table。

3.Where条件限制了查询返回的行,但是不影响层次关系,属于将节点截断,但是这个被截断的节点的下层child不受影响。

4.Start with是表示开始节点,对于一个真实的层次关系,必须要有这个子句,但是不是必须的。

5.connect by prior是指定父子关系,其中prior的位置不一定要在connect by之后,对于一个真实的层次关系,这也是必须的。

对于from是视图的,那么这个view不能包含join。

层次查询限制

1.层次查询from之后如果是table,只能是一个table,不能有join。

2.from之后如果是view,则view不能是带join的。

3.使用order by子句,order子句是在等级层次做完之后开始的,所以对于层次查询来说没有什么意义,除非特别关注level,获得某行在层次中的深度,但是这两种都会破坏层次。见增强特性中的使用siblings排序。

4.在start with中表达式可以有子查询,但是connect by中不能有子查询。

层次查询的增强特性

1、SYS_CONNECT_BY_PATH

Oracle 9i提供了sys_connect_by_path(column,char),其中column是字符型或能自动转换成字符型的列名。它的主要目的就是将父节点到当前节点的”path”按照指定的模式展现出现。这个函数只能使用在层次查询中。

下面的是oracle10g新增特性

2、CONNECT_BY_ISLEAF

   在oracle9i的时候,查找指定root下的叶子节点,是很复杂的,oracle10g引入了一个新的函数,connect_by_isleaf,如果行的值为0表示不是叶子节点,1表示是叶子节点。

3、CONNECT_BY_ISCYCLE和NOCYCLE关键字

   如果从root节点开始找其子孙,找到一行,结果发生和祖先互为子孙的情况,则发生循环,oracle会报ORA-01436: CONNECT BY loop in user data,在9i中只能将发生死循环的不加入到树中或删除,在10g中可以用nocycle关键字加在connect by之后,避免循环的参加查询操作。并且通过connect_by_iscycle得到哪个节点发生循环。0表示未发生循环,1表示发生了循环。

4、CONNECT_BY_ROOT

   Oracle10g新增connect_by_root,用在列名之前表示此行的根节点的相同列名的值。

5、使用SIBLINGS关键字排序

   对于层次查询如果用order by排序,比如order by last_name则是先做完层次获得level,然后按last_name排序,这样破坏了层次,比如特别关注某行的深度,按level排序,也是会破坏层次的。

    在oracle10g中,增加了siblings关键字的排序。

语法:ordersiblings  by

它会保护层次,并且在每个等级中按expre排序。

 

例题:

select level,ename
from emp
start with ename='KING'
connect by prior empno=mgr;

start with 子句决定了爬树的起点
connect by prior 主键=外键 子句决定了爬树的方向:
主键在前是从上向下爬(反之亦反)

col ename for a30
select level,lpad(ename,length(ename)+level*2-2,' ') ename
from emp
start with ename='KING'
connect by prior empno=mgr;

树状结构平铺:
select sys_connect_by_path(ename,'/') ename
from emp
start with ename='KING'
connect by prior empno=mgr
and ename!='BLAKE';

剪枝:
剪枝条件出现在where子句,剪一个节点
select level,lpad(ename,length(ename)+level*2-2,' ') ename
from emp
where ename!='BLAKE'
start with ename='KING'
connect by prior empno=mgr;

剪枝条件出现在connect by prior子句,剪一个分支
select level,lpad(ename,length(ename)+level*2-2,' ') ename
from emp
start with ename='KING'
connect by prior empno=mgr
and ename!='BLAKE';

 

 收藏 

 分享

https://blog.csdn.net/m0_37298602/article/details/77472942

 

 

 

 

 

 

 

https://blog.csdn.net/ycb1689/article/details/43937089

Oracle中使用Start With connect by prior实现树功能

2015年02月25日 14:01:38 ycb1689 阅读数:655

 
  1. select '|' || lpad(level, level * 4 + 1, '_') || '' ||a. member_name member_cname,

  2. a.member_type,

  3. decode(a.member_type,'加盟店',decode(a.MEMBER_LEVEL,1,'专门店','2','指导级店','3','资深指导级店','4','地区督导','5','全国督导','6','其它')

  4. ,'咨询师',decode(a.MEMBER_LEVEL,'0','申请中','1','初阶','2','中阶','3','高阶'))member_level,

  5. a.member_code,

  6. a.ALONE_BV s_bv,

  7. a.TUANDUI_BV t_bv,

  8. a.PROVINCE province_name,

  9. a.city region_name

  10. from (select

  11. member_name,

  12. MEMBER_TYPE,

  13. max(MEMBER_LEVEL) MEMBER_LEVEL,

  14. MEMBER_CODE,

  15. nvl(sum(ALONE_BV),0) ALONE_BV,

  16. nvl(sum(TUANDUI_BV),0) TUANDUI_BV,

  17. PROVINCE,

  18. CITY,

  19. RECOMMEND_CODE

  20. from ALL_MEMBERS_YJ

  21. where year>=[year_from] and month>=[month_from]

  22. and year<=[year_to] and month<=[month_to]

  23. and is_cancel=decode([s_cancle],'4',is_cancel,'1','1',is_cancel)

  24. group by member_name,MEMBER_TYPE,MEMBER_CODE,PROVINCE,CITY,RECOMMEND_CODE)a

  25. start with a.member_code =[member_code]

  26. connect by prior a.member_code = a.recommend_code

 

 收藏 

 分享

https://blog.csdn.net/ycb1689/article/details/43937089

 

 

 

 

 

 

 

https://blog.csdn.net/wacthamu/article/details/8139713

oracle 递归 start with connect by level

2012年11月02日 10:32:39 wacthamu 阅读数:4180

查找员工编号为7369的领导:

1 SELECT LEVEL,E.* FROM EMP E CONNECT BY PRIOR E.MGR = E.EMPNO  START WITH E.EMPNO = 7876
2 ORDER BY LEVEL DESC

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第7张图片

"start with" -- this identifies all LEVEL=1 nodes in the tree

"connect by" -- describes how to walk from the parent nodes above to their children and 
their childrens children.

Easiest to use an example on emp. If we start with "where mgr is NULL", we generate the 
set of employees that have no mgr (they are the top of the tree). If we

CONNECT BY PRIOR EMPNO = /* current */ MGR

that will take all of the PRIOR records (the start with at first) and find all records 
such that the MGR column equals their EMPNO (find all the records of people managed by 
the people we started with).


使用WITH语句优化查询结果:优化等级

复制代码

 1 WITH A AS
 2  (SELECT MAX(LEVEL) + 1 LVL
 3     FROM EMP E
 4   CONNECT BY PRIOR E.MGR = E.EMPNO
 5    START WITH E.EMPNO = 7876
 6    ORDER BY LEVEL DESC)
 7 SELECT A.LVL 最高等级加1,
 8        LEVEL 当前等级,
 9        A.LVL - LEVEL 优化后等级,
10        E.*  FROM A,
11        EMP E CONNECT BY PRIOR E.MGR = E.EMPNO START WITH E.EMPNO = 7876 ORDER BY LEVEL DESC

复制代码

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第8张图片

查找员工编号为7839的所有下属(7839为king):

1 SELECT LEVEL 等级, E.*
2   FROM EMP E
3 CONNECT BY PRIOR E.EMPNO = E.MGR
4  START WITH E.EMPNO = 7839

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第9张图片

--构造整个的层次结构

1 select lpad(' ',level*2,' ')||ename ename, empno, mgr
2     from emp
3     START WITH MGR IS NULL
4     CONNECT BY PRIOR EMPNO = MGR

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第10张图片

So, KING is the start with set then JONES BLAKE and CLARK fall under him. Each of them 
becomes the PRIOR record in turn and their trees are expanded.


 

使用Connect By 结合 level构造虚拟行:

1 SELECT LEVEL FROM DUAL CONNECT BY LEVEL < 5

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第11张图片

使用rownum实现类似的功能:

1 SELECT LEVEL FROM DUAL CONNECT BY LEVEL < 5

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第12张图片

---------------------待续-----------------------

使用UNION ALL构造两层节点的树:

视图如下所示:

复制代码

 1 CREATE OR REPLACE VIEW TREE_VIEW AS
 2 SELECT
 3  '1' AS rootnodeid,
 4  'xxxx有限责任公司' AS treename,
 5  '-1'  AS parent_id
 6 FROM dual
 7 UNION
 8 SELECT
 9   to_char(d.deptno),
10   d.dname || '_' ||d.loc,
11   '1' AS parent_id
12  FROM dept d;

复制代码

查询语句:

1 SELECT T.*, LEVEL
2   FROM TREE_VIEW T
3  START WITH T.PARENT_ID = '-1'
4 CONNECT BY PRIOR T.ROOTNODEID = T.PARENT_ID

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第13张图片

-----以下为更新内容:

1、先查看总共有几个等级:

1 SELECT COUNT(LEVEL)
2   FROM EMP E
3 CONNECT BY PRIOR E.EMPNO = E.MGR
4  START WITH E.MGR IS NULL;

2、查看每个等级的人数。主要是通过LEVEL进行GROUP BY

1 SELECT COUNT(LEVEL)
2   FROM EMP E
3 CONNECT BY PRIOR E.EMPNO = E.MGR
4  START WITH E.MGR IS NULL
5  GROUP BY LEVEL;

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第14张图片

3、Oracle 10g提供了一个简单的connect_by_isleaf=1,

0 表示非叶子节点

1 SELECT LEVEL AS 等级, CONNECT_BY_ISLEAF AS 是否是叶子节点, E.*
2   FROM EMP E
3 CONNECT BY PRIOR E.EMPNO = E.MGR
4  START WITH E.MGR IS NULL

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第15张图片

4、SYS_CONNECT_BY_PATH

Oracle 9i提供了sys_connect_by_path(column,char),其中column 是字符型或能自动转

换成字符型的列名。它的主要目的就是将父节点到当前节点的”path”按照指定的模式展现出现。这个函数只能使用在层次查询中。

1 SELECT LEVEL AS 等级,
2        CONNECT_BY_ISLEAF AS 是否是叶子节点,
3        LPAD(' ', LEVEL * 2 - 1) || SYS_CONNECT_BY_PATH(ENAME, '=>')
4   FROM EMP E
5 CONNECT BY PRIOR E.EMPNO = E.MGR
6  START WITH E.MGR IS NULL;

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第16张图片

5、修剪树枝和节点:

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第17张图片

    过滤掉编号是7566的数据(修剪节点),他指的是把这个节点给裁掉,但是并没有破坏树结构,它的子节点还是可以正常的显示。

复制代码

1 SELECT LEVEL AS 等级,
2        CONNECT_BY_ISLEAF AS 是否是叶子节点,
3        LPAD(' ', LEVEL * 2 - 1) || SYS_CONNECT_BY_PATH(ENAME, '=>'),
4        E.*
5   FROM EMP E
6 WHERE e.empno != 7566
7 CONNECT BY PRIOR E.EMPNO = E.MGR
8  START WITH E.MGR IS NULL;

复制代码

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第18张图片

裁掉编号是7698的节点和它的子节点:

复制代码

1 SELECT LEVEL AS 等级,
2        CONNECT_BY_ISLEAF AS 是否是叶子节点,
3        LPAD(' ', LEVEL * 2 - 1) || SYS_CONNECT_BY_PATH(ENAME, '=>'),
4        E.*
5   FROM EMP E
6 CONNECT BY PRIOR E.EMPNO = E.MGR
7        AND E.EMPNO != 7698
8  START WITH E.MGR IS NULL;

复制代码

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第19张图片

6、CONNECT_BY_ROOT的使用,oracle10g新增connect_by_root,用在列名之前表示此行的根节点的相同列名的值。

复制代码

1 SELECT LEVEL AS 等级,
2        CONNECT_BY_ISLEAF AS 是否是叶子节点,
3        CONNECT_BY_ROOT ENAME,
4        LPAD(' ', LEVEL * 2 - 1) || SYS_CONNECT_BY_PATH(ENAME, '=>'),
5        E.*
6   FROM EMP E
7 CONNECT BY PRIOR E.EMPNO = E.MGR
8  START WITH E.MGR IS NULL;

复制代码

 

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第20张图片

对于层次查询如果用order by排序,比如order by last_name则是先做完层次获得level,然后按last_name 排序,这样破坏了层次,比如特别关注某行的深度,按level 排序,也是会破坏层次的。在oracle10g中,增加了siblings 关键字的排序。

语法:order siblings by

它会保护层次,并且在每个等级中按expre排序。

复制代码

1 SELECT LEVEL AS 等级,
2        CONNECT_BY_ISLEAF AS 是否是叶子节点,
3        LPAD(' ', LEVEL * 2 - 1) || SYS_CONNECT_BY_PATH(ENAME, '=>'),
4        E.*
5   FROM EMP E
6 CONNECT BY PRIOR E.EMPNO = E.MGR 
7  START WITH E.MGR IS NULL
8  ORDER SIBLINGS BY  E.ENAME;

复制代码

【Oracle】层次查询 connect by prior start with 子句用法 无限层级 无限递归次数 递归遍历树形数据记录表_第21张图片

connect_by_iscycle(存在循环,将返回1,否则返回0)

The CONNECT_BY_ISCYCLE pseudocolumn returns 1 if the current row has a child which is also its ancestor. Otherwise it returns 0. 
You can specify CONNECT_BY_ISCYCLE only if you have specified the NOCYCLE parameter of the CONNECT BY clause. NOCYCLE enables Oracle to return the results of a query that would otherwise fail because of a CONNECT BY loop in the data.

https://blog.csdn.net/wacthamu/article/details/8139713

 

 

 

 

 

 

 

https://blog.csdn.net/NIan_jun/article/details/8826479

Oracle Connect by细说

2013年04月19日 23:55:23 nian_jun 阅读数:1982

 

   一、利用Connect by 构造数列

 

 

select level from dual connect by level <=10

 


    可用于解决百钱买鸡等列方程式问题:

 

    题:老母鸡2块1只,小母鸡2块3只,大白兔3块1只,小白兔7块4只,要求买回来的动物总共100只,并且脚不少于220条不多于340条。输出所有的可能情况,每种动物都至少要购买一只。

  解:

 

 
  1. with l as (select rownum n from dual connect by level <50 ),

  2. x as (select rownum*3 n from dual connect by level <50 ),

  3. d as (select rownum n from dual connect by level <33 ),

  4. xb as (select rownum*4 n from dual connect by level <15 )

  5. select l.n LMJ, x.n XMJ, d.n DBT, xb.n XBT

  6. from l, x, d, xb

  7. where l.n * 2 + x.n * 2 / 3 + d.n * 3 + xb.n * 7 / 4 = 100

  8. and 2 * (l.n + x.n) + 4 * (d.n + xb.n) between 220 and 340

  9. and l.n + x.n + d.n + xb.n = 100

  10. and (l.n + x.n) between 30 and 90

  11. and (d.n + xb.n) between 10 and 70 --多余限制条件为提高效率

 

二、 START WITH .. CONNECT BY PRIOR..

 

oracle中的select语句可以用START WITH...CONNECT BY PRIOR子句实现递归查询,connect by 是结构化查询中用到的,其基本语法是:

select ... from  where  start with  connect by  ;

:过滤条件,用于对返回的所有记录进行过滤。

:是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。

  :是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR org_id = parent_id就是说上一条记录的org_id 是本条记录的parent_id,即本记录的父亲是上一条记录。

早扫描树结构表时,需要依此访问树结构的每个节点,一个节点只能访问一次,其访问的步骤如下:

第一步:从根节点开始;

第二步:访问该节点;

第三步:判断该节点有无未被访问的子节点,若有,则转向它最左侧的未被访问的子节,并执行第二步,否则执行第四步;

第四步:若该节点为根节点,则访问完毕,否则执行第五步;

第五步:返回到该节点的父节点,并执行第三步骤。

总之:扫描整个树结构的过程也即是中序遍历树的过程。

1. 树结构的描述

树结构的数据存放在表中,数据之间的层次关系即父子关系,通过表中的列与列间的关系来描述,如EMP表中的EMPNO和MGR。EMPNO表示该雇员的编号,MGR表示领导该雇员的人的编号,即子节点的MGR值等于父节点的EMPNO值。在表的每一行中都有一个表示父节点的MGR(除根节点外),通过每个节点的父节点,就可以确定整个树结构。

在SELECT命令中使用CONNECT BY 和蔼START WITH 子句可以查询表中的树型结构关系。其命令格式如下:

SELECT 。。。

CONNECT BY {PRIOR 列名1=列名2|列名1=PRIOR 裂名2}

[START WITH];

其中:CONNECT BY子句说明每行数据将是按层次顺序检索,并规定将表中的数据连入树型结构的关系中。PRIORY运算符必须放置在连接关系的两列中某一个的前面。对于节点间的父子关系,PRIOR运算符在一侧表示父节点,在另一侧表示子节点,从而确定查找树结构是的顺序是自顶向下还是自底向上。在连接关系中,除了可以使用列名外,还允许使用列表达式。START WITH 子句为可选项,用来标识哪个节点作为查找树型结构的根节点。若该子句被省略,则表示所有满足查询条件的行作为根节点。

START WITH: 不但可以指定一个根节点,还可以指定多个根节点。

2.关于PRIOR

运算符PRIOR被放置于等号前后的位置,决定着查询时的检索顺序。

PRIOR被置于CONNECT BY子句中等号的前面时,则强制从根节点到叶节点的顺序检索,即由父节点向子节点方向通过树结构,我们称之为自顶向下的方式。如:

CONNECT BY PRIOR EMPNO=MGR

PIROR运算符被置于CONNECT BY 子句中等号的后面时,则强制从叶节点到根节点的顺序检索,即由子节点向父节点方向通过树结构,我们称之为自底向上的方式。例如:

CONNECT BY EMPNO=PRIOR MGR

在这种方式中也应指定一个开始的节点。

3. 定义查找起始节点

在自顶向下查询树结构时,不但可以从根节点开始,还可以定义任何节点为起始节点,以此开始向下查找。这样查找的结果就是以该节点为开始的结构树的一枝。

4.使用LEVEL

在具有树结构的表中,每一行数据都是树结构中的一个节点,由于节点所处的层次位置不同,所以每行记录都可以有一个层号。层号根据节点与根节点的距离确定。不论从哪个节点开始,该起始根节点的层号始终为1,根节点的子节点为2。

5.节点和分支的裁剪

在对树结构进行查询时,可以去掉表中的某些行,也可以剪掉树中的一个分支,使用WHERE子句来限定树型结构中的单个节点,以去掉树中的单个节点,但它却不影响其后代节点(自顶向下检索时)或前辈节点(自底向顶检索时)。

6.排序显示

象在其它查询中一样,在树结构查询中也可以使用ORDER BY 子句,改变查询结果的显示顺序,而不必按照遍历树结构的顺序。

例:

 

 
  1. create table t2(

  2. root_id number,

  3. id number,

  4. name varchar(5),

  5. description varchar(10)

  6. );

  7. insert into t2(root_id,id,name,description) values(0,1,'a','aaa');

  8. insert into t2(root_id,id,name,description) values(1,2,'a1','aaa1');

  9. insert into t2(root_id,id,name,description) values(1,3,'a2','aaa2');

  10. insert into t2(root_id,id,name,description) values(0,4,'b','bbb');

  11. insert into t2(root_id,id,name,description) values(4,5,'b1','bbb1');

  12. insert into t2(root_id,id,name,description) values(4,6,'b2','bbb2');

  13. select * from t2;

  14. select * from t2 start with root_id =0 connect by prior id= root_id;

 

三 深入了解 

 

1.  深入理解connect by  (帖子地址)

对单记录/单条数据使用connect by 正常,多条使用需要注意,其本质为每一条记录都作为自己或者其他记录的叶子进行连接

 

select id,level from t connect by level<4; 

 

其自连接的39条结果分布为

 

用sql直观展示为(38#)

 
  1. select rownum,

  2. level,

  3. sys_connect_by_path(id, ',') path,

  4. id,

  5. connect_by_isleaf isleaf

  6. from t

  7. connect by nocycle level < 4

  8. order by rownum, level, path;

 

2. GROUP BY 已知name 和name出现次数反求数据

 

a

 

 
  1. WITH data AS (

  2. SELECT 'A' name, 2 cnt FROM DUAL

  3. UNION ALL SELECT 'B', 4 FROM DUAL

  4. UNION ALL SELECT 'C', 1 FROM DUAL

  5. )

  6. SELECT name

  7. FROM data

  8. CONNECT BY name=PRIOR name AND LEVEL<=cnt ANDPRIOR SYS_GUID() IS NOT NULL;

 

其中连接条件PRIOR SYS_GUID() IS NOT NULL 的解释为:

CONNECT BY 相当于是一个递归的自连接,不断地把每层的连接结果叠加到结果集中。两层之间的连接条件和递归出口写在CONNECT BY中。
在这的数据并无父子关系,只是要让同一行数据重复出现,因此连接的条件只用到了表的主键id=PRIOR id, 此外再用LEVEL控制层数作为递归出口
。但ORACLE有个检查,如果你有前后连接条件(id=PRIOR id),但是同一行数据再次出现,
它就会报一个错:ERROR:ORA-01436: CONNECT BY loop in user data
为了欺骗它,这里用了一个PRIOR DBMS_RANDOM.VALUE, 因为DBMS_RANDOM.VALUE每次调用都返回不同结果,所以它认为两行数据不一样,所以不报错了。

递归写法

 
  1. WITH data AS (

  2. SELECT 'A' name, 2 cnt FROM DUAL

  3. UNION ALL SELECT 'B', 4 FROM DUAL

  4. UNION ALL SELECT 'C', 1 FROM DUAL

  5. ),

  6. rdata (name, cnt, lv) as

  7. (

  8. select name, cnt, 1 as lv from data

  9. union all

  10. select name, cnt, lv + 1 as lv from rdata where lv + 1 <= cnt

  11. )

  12. select * from rdata

  13. order by name, lv;

 

 

以上资料大多为论坛学习资料总结和整理,深入学习connect by

 

 收藏 

 分享

https://blog.csdn.net/NIan_jun/article/details/8826479

 

 

 

 

 

 

https://blog.csdn.net/wangshfa/article/details/23780249

leve,connect_by_isleaf,connect_by_iscycle伪列

2014年04月15日 19:00:46 wangshfa 阅读数:1968更多

个人分类: oracle

level,connect_by_isleaf,connect_by_iscycle伪列

level 就是这个数据属于 哪一个等级,比如PRESIDENT为1,MANAGER为2

connect_by_isleaf 就是树的最末端的值,或者说这个树枝下已经没有树叶了

connect_by_iscycle  导致出现死循环的那个树枝

 

查询scott 的emp 表

SQL> select empno,level,rpad('*',level,'*')||ename name,job,mgr from emp start with empno=7839 connect by prior empno=mgr;
 
EMPNO      LEVEL NAME         JOB         MGR
----- ---------- ------------ --------- -----
 7839          1 *KING        PRESIDENT                --level 为1
 7566          2 **JONES      MANAGER    7839          --level 为2
 7788          3 ***SCOTT     ANALYST    7566
 7876          4 ****ADAMS    CLERK      7788
 7902          3 ***FORD      ANALYST    7566
 7369          4 ****SMITH    CLERK      7902
 7698          2 **BLAKE      MANAGER    7839
 7499          3 ***ALLEN     SALESMAN   7698
 7521          3 ***WARD      SALESMAN   7698
 7654          3 ***MARTIN    SALESMAN   7698
 7844          3 ***TURNER    SALESMAN   7698
 7900          3 ***JAMES     CLERK      7698

https://blog.csdn.net/wangshfa/article/details/23780249

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Oracle,数据库,算法,层次查询,递归遍历树,connect,by,prior,Oracle,oracle,manager,path,up,user,数据库,oracle)