如果至少有一个节点处于活动状态,则打印层次结构中的所有节点
Print all nodes in a hierarchy if at least one node is active
A table EMPLOYEE 具有以下结构,其中包含 500 万行 (5 * 106)。
Name
------
EMPNAME
EMPID
MANAGERID (foreign key to same table)
STATUS
table 上的 ManagerId 自联接导致系统中出现多个层次结构。层次结构最高为 5 级。
我需要一种最佳方法来获取层次结构中的所有节点,该层次结构可能至少有一个节点处于活动状态 (1,2,3)。
此输出将存储在具有类似 table 结构的 table 中。
可能有多个根。
之前曾尝试使用此查询,但它不正确,因为它不涉及递归。
SELECT empname, empid
FROM employee e
WHERE e.status in (1,2,3)
OR
e.managerid IN (SELECT empid
FROM employee m
WHERE e.status in (1,2,3))
示例场景:
EMPNAME | EMPID | MANAGERID | STATUS
:-------- | ----: | --------: | -----:
CEO | 1 | NULL | 0
Mgr1 | 2 | 1 | 1
Mgr2 | 3 | 1 | 0
Mgr3 | 4 | 1 | 0
SubMgr1.1 | 5 | 2 | 0
SubMgr1.2 | 6 | 2 | 1
SubMgr2.1 | 7 | 3 | 0
SubMgr2.2 | 8 | 3 | 1
SubMgr3.1 | 9 | 4 | 0
Emp1.1.1 | 10 | 5 | 0
Emp1.1.2 | 11 | 5 | 1
Emp1.2.1 | 12 | 6 | 0
Emp1.2.2 | 13 | 6 | 1
Emp2.1.1 | 14 | 7 | 0
Emp2.1.2 | 15 | 7 | 1
Emp2.2.1 | 16 | 8 | 0
Emp2.2.2 | 17 | 8 | 1
Emp3.1.1 | 18 | 9 | 0
Emp3.1.2 | 19 | 9 | 1
在此示例中,Mgr1 的状态为 1
因此,应选择 Mgr1 下的所有员工和高于 Mgr1(CEO)的员工。
同样,Emp3.1.2(叶节点)处于活动状态 - 因此包括此 Emp3.1.2 的所有管理人员(SubMgr3.1、Mgr3、CEO),即使上述人员处于非活动状态。
预期输出(将最佳存储在不同的 table 中):
EMPNAME | EMPID | MANAGERID | STATUS
:-------- | ----: | --------: | -----:
CEO | 1 | null | 0
Mgr1 | 2 | 1 | 1
SubMgr1.1 | 5 | 2 | 0
Emp1.1.1 | 10 | 5 | 0
Emp1.1.2 | 11 | 5 | 1
SubMgr1.2 | 6 | 2 | 1
Emp1.2.1 | 12 | 6 | 0
Emp1.2.2 | 13 | 6 | 1
Mgr2 | 3 | 1 | 0
SubMgr2.1 | 7 | 3 | 0
Emp2.1.2 | 15 | 7 | 1
SubMgr2.2 | 8 | 3 | 1
Emp2.2.1 | 16 | 8 | 0
Emp2.2.2 | 17 | 8 | 1
Mgr3 | 4 | 1 | 0
SubMgr3.1 | 9 | 4 | 0
Emp3.1.2 | 19 | 9 | 1
这将获得完整的未过滤层次结构(假设顶级经理具有 managerid
的 NULL
值):
SELECT *
FROM table_name
START WITH MANAGERID IS NULL
CONNECT BY PRIOR EMPID = MANAGERID
然后您可以过滤以查看层次结构中是否存在从每个员工备份到顶级经理的活动状态:
SELECT *
FROM table_name t
WHERE EXISTS (
SELECT 1
FROM table_name
WHERE status IN (1,2,3)
START WITH EMPID = t.EMPID
CONNECT BY EMPID = PRIOR MANAGERID
)
START WITH MANAGERID IS NULL
CONNECT BY PRIOR EMPID = MANAGERID
其中为测试数据:
CREATE TABLE table_name ( EMPNAME, EMPID, MANAGERID, STATUS ) AS
SELECT 'CEO', 1, NULL, 0 FROM DUAL UNION ALL
SELECT 'Mgr1', 2, 1, 1 FROM DUAL UNION ALL
SELECT 'Mgr2', 3, 1, 0 FROM DUAL UNION ALL
SELECT 'Mgr3', 4, 1, 0 FROM DUAL UNION ALL
SELECT 'SubMgr1.1', 5, 2, 0 FROM DUAL UNION ALL
SELECT 'SubMgr1.2', 6, 2, 1 FROM DUAL UNION ALL
SELECT 'SubMgr2.1', 7, 3, 0 FROM DUAL UNION ALL
SELECT 'SubMgr2.2', 8, 3, 1 FROM DUAL UNION ALL
SELECT 'SubMgr3.1', 9, 4, 0 FROM DUAL UNION ALL
SELECT 'Emp1.1.1', 10, 5, 0 FROM DUAL UNION ALL
SELECT 'Emp1.1.2', 11, 5, 1 FROM DUAL UNION ALL
SELECT 'Emp1.2.1', 12, 6, 0 FROM DUAL UNION ALL
SELECT 'Emp1.2.2', 13, 6, 1 FROM DUAL UNION ALL
SELECT 'Emp2.1.1', 14, 7, 0 FROM DUAL UNION ALL
SELECT 'Emp2.1.2', 15, 7, 1 FROM DUAL UNION ALL
SELECT 'Emp2.2.1', 16, 8, 0 FROM DUAL UNION ALL
SELECT 'Emp2.2.2', 17, 8, 1 FROM DUAL UNION ALL
SELECT 'Emp3.1.1', 18, 9, 0 FROM DUAL UNION ALL
SELECT 'Emp3.1.2', 19, 9, 1 FROM DUAL;
给出输出:
EMPNAME | EMPID | MANAGERID | STATUS
:-------- | ----: | --------: | -----:
Mgr1 | 2 | 1 | 1
SubMgr1.1 | 5 | 2 | 0
Emp1.1.1 | 10 | 5 | 0
Emp1.1.2 | 11 | 5 | 1
SubMgr1.2 | 6 | 2 | 1
Emp1.2.1 | 12 | 6 | 0
Emp1.2.2 | 13 | 6 | 1
Emp2.1.2 | 15 | 7 | 1
SubMgr2.2 | 8 | 3 | 1
Emp2.2.1 | 16 | 8 | 0
Emp2.2.2 | 17 | 8 | 1
Emp3.1.2 | 19 | 9 | 1
要在两个方向上进行检查,则只需降低层次结构并提高层次结构即可:
SELECT *
FROM table_name t
WHERE EXISTS (
SELECT 1
FROM table_name
WHERE status IN (1,2,3)
START WITH EMPID = t.MANAGERID
CONNECT BY EMPID = PRIOR MANAGERID
UNION ALL
SELECT 1
FROM table_name
WHERE status IN (1,2,3)
START WITH EMPID = t.EMPID
CONNECT BY PRIOR EMPID = MANAGERID
)
START WITH MANAGERID IS NULL
CONNECT BY PRIOR EMPID = MANAGERID
输出:
EMPNAME | EMPID | MANAGERID | STATUS
:-------- | ----: | --------: | -----:
CEO | 1 | null | 0
Mgr1 | 2 | 1 | 1
SubMgr1.1 | 5 | 2 | 0
Emp1.1.1 | 10 | 5 | 0
Emp1.1.2 | 11 | 5 | 1
SubMgr1.2 | 6 | 2 | 1
Emp1.2.1 | 12 | 6 | 0
Emp1.2.2 | 13 | 6 | 1
Mgr2 | 3 | 1 | 0
SubMgr2.1 | 7 | 3 | 0
Emp2.1.2 | 15 | 7 | 1
SubMgr2.2 | 8 | 3 | 1
Emp2.2.1 | 16 | 8 | 0
Emp2.2.2 | 17 | 8 | 1
Mgr3 | 4 | 1 | 0
SubMgr3.1 | 9 | 4 | 0
Emp3.1.2 | 19 | 9 | 1
db<>fiddle here
您还可以使用递归子查询分解子句在层次结构中下降时传播活动状态;如果它不活动,您仍然需要检查另一个方向的剩余层次结构。分析这两种解决方案,看看一个是否比另一个更高效,因为我们无法确定。
WITH data ( empname, empid, managerid, status, is_active ) AS (
SELECT t.empname,
t.empid,
t.managerid,
t.status,
CASE WHEN status IN (1,2,3) THEN 1 ELSE 0 END
FROM table_name t
WHERE managerid IS NULL
UNION ALL
SELECT t.empname,
t.empid,
t.managerid,
t.status,
CASE WHEN d.is_active = 1 OR t.status IN (1,2,3) THEN 1 ELSE 0 END
FROM data d
INNER JOIN table_name t
ON ( d.empid = t.managerid )
)
SELECT empname,
empid,
managerid,
status
FROM data d
WHERE is_active = 1
OR EXISTS (
SELECT 1
FROM table_name t
WHERE t.status IN ( 1, 2, 3)
START WITH d.empid = t.managerid
CONNECT BY PRIOR empid = managerid
)
A table EMPLOYEE 具有以下结构,其中包含 500 万行 (5 * 106)。
Name
------
EMPNAME
EMPID
MANAGERID (foreign key to same table)
STATUS
table 上的 ManagerId 自联接导致系统中出现多个层次结构。层次结构最高为 5 级。
我需要一种最佳方法来获取层次结构中的所有节点,该层次结构可能至少有一个节点处于活动状态 (1,2,3)。 此输出将存储在具有类似 table 结构的 table 中。 可能有多个根。
之前曾尝试使用此查询,但它不正确,因为它不涉及递归。
SELECT empname, empid
FROM employee e
WHERE e.status in (1,2,3)
OR
e.managerid IN (SELECT empid
FROM employee m
WHERE e.status in (1,2,3))
示例场景:
EMPNAME | EMPID | MANAGERID | STATUS
:-------- | ----: | --------: | -----:
CEO | 1 | NULL | 0
Mgr1 | 2 | 1 | 1
Mgr2 | 3 | 1 | 0
Mgr3 | 4 | 1 | 0
SubMgr1.1 | 5 | 2 | 0
SubMgr1.2 | 6 | 2 | 1
SubMgr2.1 | 7 | 3 | 0
SubMgr2.2 | 8 | 3 | 1
SubMgr3.1 | 9 | 4 | 0
Emp1.1.1 | 10 | 5 | 0
Emp1.1.2 | 11 | 5 | 1
Emp1.2.1 | 12 | 6 | 0
Emp1.2.2 | 13 | 6 | 1
Emp2.1.1 | 14 | 7 | 0
Emp2.1.2 | 15 | 7 | 1
Emp2.2.1 | 16 | 8 | 0
Emp2.2.2 | 17 | 8 | 1
Emp3.1.1 | 18 | 9 | 0
Emp3.1.2 | 19 | 9 | 1
在此示例中,Mgr1 的状态为 1 因此,应选择 Mgr1 下的所有员工和高于 Mgr1(CEO)的员工。
同样,Emp3.1.2(叶节点)处于活动状态 - 因此包括此 Emp3.1.2 的所有管理人员(SubMgr3.1、Mgr3、CEO),即使上述人员处于非活动状态。
预期输出(将最佳存储在不同的 table 中):
EMPNAME | EMPID | MANAGERID | STATUS
:-------- | ----: | --------: | -----:
CEO | 1 | null | 0
Mgr1 | 2 | 1 | 1
SubMgr1.1 | 5 | 2 | 0
Emp1.1.1 | 10 | 5 | 0
Emp1.1.2 | 11 | 5 | 1
SubMgr1.2 | 6 | 2 | 1
Emp1.2.1 | 12 | 6 | 0
Emp1.2.2 | 13 | 6 | 1
Mgr2 | 3 | 1 | 0
SubMgr2.1 | 7 | 3 | 0
Emp2.1.2 | 15 | 7 | 1
SubMgr2.2 | 8 | 3 | 1
Emp2.2.1 | 16 | 8 | 0
Emp2.2.2 | 17 | 8 | 1
Mgr3 | 4 | 1 | 0
SubMgr3.1 | 9 | 4 | 0
Emp3.1.2 | 19 | 9 | 1
这将获得完整的未过滤层次结构(假设顶级经理具有 managerid
的 NULL
值):
SELECT *
FROM table_name
START WITH MANAGERID IS NULL
CONNECT BY PRIOR EMPID = MANAGERID
然后您可以过滤以查看层次结构中是否存在从每个员工备份到顶级经理的活动状态:
SELECT *
FROM table_name t
WHERE EXISTS (
SELECT 1
FROM table_name
WHERE status IN (1,2,3)
START WITH EMPID = t.EMPID
CONNECT BY EMPID = PRIOR MANAGERID
)
START WITH MANAGERID IS NULL
CONNECT BY PRIOR EMPID = MANAGERID
其中为测试数据:
CREATE TABLE table_name ( EMPNAME, EMPID, MANAGERID, STATUS ) AS
SELECT 'CEO', 1, NULL, 0 FROM DUAL UNION ALL
SELECT 'Mgr1', 2, 1, 1 FROM DUAL UNION ALL
SELECT 'Mgr2', 3, 1, 0 FROM DUAL UNION ALL
SELECT 'Mgr3', 4, 1, 0 FROM DUAL UNION ALL
SELECT 'SubMgr1.1', 5, 2, 0 FROM DUAL UNION ALL
SELECT 'SubMgr1.2', 6, 2, 1 FROM DUAL UNION ALL
SELECT 'SubMgr2.1', 7, 3, 0 FROM DUAL UNION ALL
SELECT 'SubMgr2.2', 8, 3, 1 FROM DUAL UNION ALL
SELECT 'SubMgr3.1', 9, 4, 0 FROM DUAL UNION ALL
SELECT 'Emp1.1.1', 10, 5, 0 FROM DUAL UNION ALL
SELECT 'Emp1.1.2', 11, 5, 1 FROM DUAL UNION ALL
SELECT 'Emp1.2.1', 12, 6, 0 FROM DUAL UNION ALL
SELECT 'Emp1.2.2', 13, 6, 1 FROM DUAL UNION ALL
SELECT 'Emp2.1.1', 14, 7, 0 FROM DUAL UNION ALL
SELECT 'Emp2.1.2', 15, 7, 1 FROM DUAL UNION ALL
SELECT 'Emp2.2.1', 16, 8, 0 FROM DUAL UNION ALL
SELECT 'Emp2.2.2', 17, 8, 1 FROM DUAL UNION ALL
SELECT 'Emp3.1.1', 18, 9, 0 FROM DUAL UNION ALL
SELECT 'Emp3.1.2', 19, 9, 1 FROM DUAL;
给出输出:
EMPNAME | EMPID | MANAGERID | STATUS :-------- | ----: | --------: | -----: Mgr1 | 2 | 1 | 1 SubMgr1.1 | 5 | 2 | 0 Emp1.1.1 | 10 | 5 | 0 Emp1.1.2 | 11 | 5 | 1 SubMgr1.2 | 6 | 2 | 1 Emp1.2.1 | 12 | 6 | 0 Emp1.2.2 | 13 | 6 | 1 Emp2.1.2 | 15 | 7 | 1 SubMgr2.2 | 8 | 3 | 1 Emp2.2.1 | 16 | 8 | 0 Emp2.2.2 | 17 | 8 | 1 Emp3.1.2 | 19 | 9 | 1
要在两个方向上进行检查,则只需降低层次结构并提高层次结构即可:
SELECT *
FROM table_name t
WHERE EXISTS (
SELECT 1
FROM table_name
WHERE status IN (1,2,3)
START WITH EMPID = t.MANAGERID
CONNECT BY EMPID = PRIOR MANAGERID
UNION ALL
SELECT 1
FROM table_name
WHERE status IN (1,2,3)
START WITH EMPID = t.EMPID
CONNECT BY PRIOR EMPID = MANAGERID
)
START WITH MANAGERID IS NULL
CONNECT BY PRIOR EMPID = MANAGERID
输出:
EMPNAME | EMPID | MANAGERID | STATUS :-------- | ----: | --------: | -----: CEO | 1 | null | 0 Mgr1 | 2 | 1 | 1 SubMgr1.1 | 5 | 2 | 0 Emp1.1.1 | 10 | 5 | 0 Emp1.1.2 | 11 | 5 | 1 SubMgr1.2 | 6 | 2 | 1 Emp1.2.1 | 12 | 6 | 0 Emp1.2.2 | 13 | 6 | 1 Mgr2 | 3 | 1 | 0 SubMgr2.1 | 7 | 3 | 0 Emp2.1.2 | 15 | 7 | 1 SubMgr2.2 | 8 | 3 | 1 Emp2.2.1 | 16 | 8 | 0 Emp2.2.2 | 17 | 8 | 1 Mgr3 | 4 | 1 | 0 SubMgr3.1 | 9 | 4 | 0 Emp3.1.2 | 19 | 9 | 1
db<>fiddle here
您还可以使用递归子查询分解子句在层次结构中下降时传播活动状态;如果它不活动,您仍然需要检查另一个方向的剩余层次结构。分析这两种解决方案,看看一个是否比另一个更高效,因为我们无法确定。
WITH data ( empname, empid, managerid, status, is_active ) AS (
SELECT t.empname,
t.empid,
t.managerid,
t.status,
CASE WHEN status IN (1,2,3) THEN 1 ELSE 0 END
FROM table_name t
WHERE managerid IS NULL
UNION ALL
SELECT t.empname,
t.empid,
t.managerid,
t.status,
CASE WHEN d.is_active = 1 OR t.status IN (1,2,3) THEN 1 ELSE 0 END
FROM data d
INNER JOIN table_name t
ON ( d.empid = t.managerid )
)
SELECT empname,
empid,
managerid,
status
FROM data d
WHERE is_active = 1
OR EXISTS (
SELECT 1
FROM table_name t
WHERE t.status IN ( 1, 2, 3)
START WITH d.empid = t.managerid
CONNECT BY PRIOR empid = managerid
)