深度级别的 Oracle 分层查询

Oracle Hierarchical Query at depth level

我需要从分层 table 构建 table。 Table结构如下:

emp_hier table:

emp_id supervisorId
100 null
1 100
2 1
3 2

新建table:

我必须在 emp_heir table 上编写一个 select 查询,selected 数据应该如下所示:

sel_emp_id rel_emp_id relation depth_lvl
100 100 self 0
100 1 My Repotee -1
100 2 My Repotee -2
100 3 My Repotee -3
1 100 My Mgr 1
1 1 self 0
1 2 My Repotee -1
1 3 My Repotee -2
2 1 My Mgr 1
2 2 self 0
2 3 My Repotee -1
3 100 My Mgr 3
3 1 My Mgr 2
3 2 My Mgr 1
3 3 self 0

使用CONNECT BY,您可以将所有员工及其关系连接起来。然后通过将这些信息连接在一起,您可以按照您想要的格式打印出这些信息。

WITH
    hier
    AS
        (    SELECT e.*, LEVEL AS lvl
               FROM emp_hier e
         CONNECT BY PRIOR emp_id = supervisorid
         START WITH supervisorid IS NULL)
  SELECT h1.emp_id          AS sel_emp_id,
         h2.emp_id          AS rel_emp_id,
         CASE
             WHEN h1.lvl - h2.lvl = 0 THEN 'self'
             WHEN h1.lvl - h2.lvl > 0 THEN 'My Mgr'
             ELSE 'My Reportee'
         END                AS relation,
         h1.lvl - h2.lvl    AS depth_level
    FROM hier h1, hier h2
ORDER BY CASE WHEN h1.supervisorid IS NULL THEN 0 ELSE 1 END, h1.emp_id, h1.lvl - h2.lvl DESC;



   SEL_EMP_ID    REL_EMP_ID       RELATION    DEPTH_LEVEL
_____________ _____________ ______________ ______________
          100           100 self                        0
          100             1 My Reportee                -1
          100             2 My Reportee                -2
          100             3 My Reportee                -3
            1           100 My Mgr                      1
            1             1 self                        0
            1             2 My Reportee                -1
            1             3 My Reportee                -2
            2           100 My Mgr                      2
            2             1 My Mgr                      1
            2             2 self                        0
            2             3 My Reportee                -1
            3           100 My Mgr                      3
            3             1 My Mgr                      2
            3             2 My Mgr                      1
            3             3 self                        0

您可以使用 UNION ALL 组合一个分层查询来获取每一行及其子行到另一个分层查询来获取所有祖先:

SELECT CONNECT_BY_ROOT emp_id AS sel_emp_id,
       emp_id AS rel_emp_id,
       CASE LEVEL WHEN 1 THEN 'Self' ELSE 'My Reportee' END AS relation,
       1 - LEVEL AS depth_lvl
FROM   emp_hier
CONNECT BY PRIOR emp_id = supervisorid
UNION ALL
SELECT CONNECT_BY_ROOT emp_id,
       emp_id,
       'My Mgr',
       LEVEL - 1
FROM   emp_hier
WHERE  LEVEL > 1
CONNECT BY PRIOR supervisorid = emp_id
ORDER BY sel_emp_id, depth_lvl DESC

其中,对于您的示例数据:

CREATE TABLE emp_hier (emp_id, supervisorId) AS
SELECT 100, null FROM DUAL UNION ALL
SELECT 1,   100  FROM DUAL UNION ALL
SELECT 2,   1    FROM DUAL UNION ALL
SELECT 3,   2    FROM DUAL;

输出:

SEL_EMP_ID REL_EMP_ID RELATION DEPTH_LVL
1 100 My Mgr 1
1 1 Self 0
1 2 My Reportee -1
1 3 My Reportee -2
2 100 My Mgr 2
2 1 My Mgr 1
2 2 Self 0
2 3 My Reportee -1
3 100 My Mgr 3
3 1 My Mgr 2
3 2 My Mgr 1
3 3 Self 0
100 100 Self 0
100 1 My Reportee -1
100 2 My Reportee -2
100 3 My Reportee -3

db<>fiddle here

您可以通过一次层次结构(单个 CONNECT BY 查询)获得完整的所需结果,没有 self-join 也没有 union all.

相反,我使用了辅助内联视图(只有一行和两个数字列,值为 -1 和 1);由于每个“关系”在输出中恰好出现两次,“自我”除外,我用它来对分层查询中的行进行 ad-hoc 复制。

我用MT0的post中的table进行测试。我没有显示结果 - 是一样的(只是顺序不同)。

with
  h (x) as (select  1 from dual union all select -1 from dual)
, p (ancestor, emp, depth) as (
    select  connect_by_root(emp_id), emp_id, level - 1
    from    emp_hier
    connect by supervisorid = prior emp_id
  )
select case h.x when 1 then emp      else ancestor end as emp_self,
       case h.x when 1 then ancestor else emp      end as emp_related,
       case when h.x      = 1 then 'Mgr'
            when p.depth != 0 then 'Reportee'
                              else 'Self'     end      as rel,
       h.x * p.depth                                   as depth_level
from   p join h on h.x = -1 or p.depth != 0   -- do not duplicate "Self"
order  by emp_self, depth_level desc, emp_related -- or whatever (if/as needed)
;