zoukankan      html  css  js  c++  java
  • Oracle Tree 树高级应用

    本文系转载,如果有侵犯您权益的地方,烦请即使告知

    1、一个比较难的SQL(Oracle 9i 实现 10G 的 CONNECT_BY_ISLEAF、CONNECT_BY_ROOT 等功能)

    参考网址:http://blog.csdn.net/wzy0623/article/details/1644049

    有一个emp表,2个字段,员工id和主管id. 1,emp_id, 2,manager_id
    假如有以下资料,一个员工可以对应一个或多个主管id,即一个员工可能有几个主管。
    emp_id manager_id
    001      101
    001      102
    101      201
    102      202
    002      102
    003      103
    103      203
    201      301
    203      303

    现在要通过任何一个员工id,能查到他的最高主管的id,可能结果不止一笔。

    即如果是001,则结果如下:
    emp_id manager_id
    001      301
    001      202
    ........................
    即如果是002,则结果如下:
    emp_id manager_id
    002      102
    ........................
    即如果是103,则结果如下:
    emp_id manager_id
    103      303
    ......................................
    以下是建表脚本及资料:

     1 CREATE TABLE emp
     2 (
     3 emp_id VARCHAR2(10 ),
     4 manager_id VARCHAR2(10 )
     5 );
     6 
     7 INSERT INTO emp
     8             (emp_id, manager_id
     9             )
    10      VALUES ('001', '101'
    11             );
    12 INSERT INTO emp
    13             (emp_id, manager_id
    14             )
    15      VALUES ('001', '102'
    16             );
    17 INSERT INTO emp
    18             (emp_id, manager_id
    19             )
    20      VALUES ('101', '201'
    21             );
    22 INSERT INTO emp
    23             (emp_id, manager_id
    24             )
    25      VALUES ('102', '202'
    26             );
    27 INSERT INTO emp
    28             (emp_id, manager_id
    29             )
    30      VALUES ('002', '102'
    31             );
    32 INSERT INTO emp
    33             (emp_id, manager_id
    34             )
    35      VALUES ('003', '103'
    36             );
    37 INSERT INTO emp
    38             (emp_id, manager_id
    39             )
    40      VALUES ('103', '203'
    41             );
    42 INSERT INTO emp
    43             (emp_id, manager_id
    44             )
    45      VALUES ('201', '301'
    46             );
    47 INSERT INTO emp
    48             (emp_id, manager_id
    49             )
    50      VALUES ('203', '303'
    51             );
    52 COMMIT ;
    View Code

    有人给出这样的答案:

    1 SELECT emp_id,
    2        manager_id
    3   FROM (SELECT connect_by_root(emp_id) emp_id,
    4                manager_id,
    5                connect_by_isleaf v_isleaf
    6           FROM emp
    7         CONNECT BY emp_id = PRIOR manager_id)
    8  WHERE v_isleaf = 1;

    这个写法非常简洁,用到了10G connect by 增强的特性,如判断是否叶子节点的伪列 CONNECT_BY_ISLEAF,只使用根行返回结果的一元操作符 CONNECT_BY_ROOT 等,很好。但提问者说使用的是 9i,这就有些麻烦了,能否使用一个 sql 而不是 plsql 实现呢?深入研究后给出了我的 sql:

    1 SELECT emp_id, manager_id
    2   FROM (SELECT FIRST_VALUE (emp_id) OVER (PARTITION BY part ORDER BY lev) emp_id,
    3                ROW_NUMBER () OVER (PARTITION BY part ORDER BY lev DESC) rn,
    4                part, manager_id AS manager_id
    5         FROM (SELECT emp_id, manager_id, LEVEL lev, (ROWNUM - LEVEL) part
    6                 FROM emp
    7               CONNECT BY emp_id = PRIOR manager_id))
    8 WHERE rn = 1;

    9i 没有提供 CONNECT_BY_ISLEAF 及 CONNECT_BY_ROOT,但可以使用分析函数实现其基本功能,下面分析一下。

    最内层的查询:

    1 SELECT emp_id, manager_id, LEVEL lev, (ROWNUM - LEVEL) part
    2 FROM emp
    3 CONNECT BY emp_id = PRIOR manager_id;

    这里用到了从叶子到跟的反向遍历,同时用 (ROWNUM - LEVEL) part 列的值表示一个从叶子到根的路径,为使用分析函数的分区条件做准备。

    二层嵌套查询

     1 SELECT first_value(emp_id) over(PARTITION BY part ORDER BY lev) emp_id,
     2        row_number() over(PARTITION BY part ORDER BY lev DESC) rn,
     3        part,
     4        manager_id AS manager_id
     5   FROM (SELECT emp_id,
     6                manager_id,
     7                LEVEL lev,
     8                (rownum - LEVEL) part
     9           FROM emp
    10         CONNECT BY emp_id = PRIOR manager_id);

    按 part 分区,以 lev 正排序,再使用 FIRST_VALUE 操作使第一列都显示叶子节点;
    按 part 分区,以 lev 倒排序,再使用 ROW_NUMBER () 函数划分等级,等级排第一的即为根节点。

    最外层嵌套查询,取得所要求的结果输出。

    I believe that we are who we choose to be. Nobody‘s going to come and save you, you‘ve got to save yourself. 我相信我们成为怎样的人是我们自己的选择。没有人会来拯救你,你必须要自己拯救自己。
  • 相关阅读:
    100个经典的动态规划方程
    poj 2105 IP Address
    codeforces 299 A. Ksusha and Array
    codeforces 305 C. Ivan and Powers of Two
    性能测试实战 | 修改 JMeter 源码,定制化聚合压测报告
    Pytest 测试框架训练营,测试大咖带你搞定自动化+接口测试实战 | 限时免费报名
    MTSC 测试开开发大会(深圳站),报名立减 100 元!
    测试人面试 BAT 大厂之前,需要做好哪些准备?
    iOS 自动化测试踩坑(二):Appium 架构原理、环境命令、定位方式
    【北京】美团打车招聘职位
  • 原文地址:https://www.cnblogs.com/caroline/p/3086152.html
Copyright © 2011-2022 走看看