• 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

  • 相关阅读:
    IO流图片加密。
    IO流(流的标准处理异常代码)
    字节流写出中文。
    字节流读取中文。
    IO流BufferedInputStream和BufferOutputStream拷贝。
    Collection集合。
    《C#并发编程经典实例》学习笔记—2.3 报告任务
    《C#并发编程经典实例》学习笔记—2.2 返回完成的任务
    《C#并发编程经典实例》学习笔记—2.1 暂停一段时间
    《C#并发编程经典实例》学习笔记—异步编程关键字 Async和Await
  • 原文地址:https://www.cnblogs.com/wcwen1990/p/7601207.html
Copyright © 2020-2023  润新知