深度级别的 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)
;
我需要从分层 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)
;