我是 Oracle 的新手,我将在实现平面表而不是分层表之前使用 connect by 。但我有点困惑。我的桌子是这样的: 员工表:
empID | 员工姓名 | 经理ID |
---|---|---|
100 | 莎拉 | 110 |
101 | 本 | 111 |
102 | 亚历克斯 | 110 |
110 | 罗斯 | 111 |
111 | 周一 | 空 |
我要像这样更改表格(输出):
员工 | 员工姓名 | 副老板 | 副老板姓名 | 老板 | 老板姓名 |
---|---|---|---|---|---|
100 | 莎拉 | 110 | 罗斯 | 111 | 周一 |
101 | 本 | 111 | 周一 | 空 | 空 |
102 | 亚历克斯 | 110 | 罗斯 | 111 | 周一 |
110 | 罗斯 | 111 | 周一 | 空 | 空 |
111 | 周一 | 空 | 空 | 空 | 空 |
您还可以使用 connect by 子句来实现此目的。
select empID, empName
, subBoss, subBossName
, (select boss.empID from YourTable boss where boss.empID = subBossManagerID) Boss
, (select boss.empName from YourTable boss where boss.empID = subBossManagerID) BossName
from (
select empID, empName
, prior empID subBoss, prior empName subBossName
, prior t.managerID subBossManagerID
from YourTable t
start with managerID is null
connect by prior empID = managerID
)
order by 1
;
Ankit Bajpai 的答案由于使用 root 连接而在 4 级之后给出了错误的管理者名称。 通过小通知,此查询给出最短的答案
WITH DATA AS (SELECT 100 AS empID, 'Sara' AS empName, 110 AS managerID FROM DUAL UNION ALL
SELECT 101, 'Ben', 111 FROM DUAL UNION ALL
SELECT 102, 'Alex', 110 FROM DUAL UNION ALL
SELECT 110, 'Ross', 111 FROM DUAL UNION ALL
SELECT 111, 'Mon', NULL FROM DUAL)
, b as( SELECT p.empID , p.empName, p.managerID, m.empName as managerName FROM DATA p left join data m
on ( p.managerID=m.empID))
SELECT empID emp, empName, prior empID subBoss, prior empName subBossName
, prior managerID Boss, prior managerName BossNAme
FROM b
START WITH managerID IS NULL
CONNECT BY PRIOR empID = managerID
ORDER BY 1;
您可以为此使用递归子查询分解子句:
WITH hierarchy (empID, empName, subBoss, subBossName, boss, bossName, depth, managerId) AS (
SELECT empID,
empName,
CAST(NULL AS NUMBER),
CAST(NULL AS VARCHAR2(20)),
CAST(NULL AS NUMBER),
CAST(NULL AS VARCHAR2(20)),
1,
managerID
FROM empTbl
UNION ALL
SELECT h.empID,
h.empName,
CASE h.depth
WHEN 1 THEN e.empID
ELSE h.subBoss
END,
CASE h.depth
WHEN 1 THEN e.empName
ELSE h.subBossName
END,
CASE h.depth
WHEN 2 THEN e.empID
ELSE h.boss
END,
CASE h.depth
WHEN 2 THEN e.empName
ELSE h.bossName
END,
h.depth + 1,
e.managerID
FROM hierarchy h
LEFT OUTER JOIN empTbl e
ON (h.managerID = e.empID)
WHERE depth < 3
)
CYCLE empID, depth SET is_cycle TO 1 DEFAULT 0
SELECT empID, empName, subBoss, subBossName, boss, bossName
FROM hierarchy
WHERE depth = 3;
或者,您可以使用分层查询和数据透视:
SELECT emp_id AS empID,
emp_name AS empName,
subboss_id AS subbossid,
subboss_name AS subbossname,
boss_id AS bossid,
boss_name AS bossname
FROM (
SELECT CONNECT_BY_ROOT(empID) AS root_empid,
empID,
empName,
LEVEL AS depth
FROM empTbl
WHERE LEVEL <= 3
CONNECT BY PRIOR managerID = empID
)
PIVOT (
MAX(empID) AS id,
MAX(empName) AS name
FOR depth IN (
1 AS emp,
2 AS subBoss,
3 AS boss
)
)
ORDER BY empid;
对于样本数据:
CREATE TABLE empTbl (empID, empName, managerID) AS
SELECT 100, 'Sara', 110 FROM DUAL UNION ALL
SELECT 101, 'Ben', 111 FROM DUAL UNION ALL
SELECT 102, 'Alex', 110 FROM DUAL UNION ALL
SELECT 110, 'Ross', 111 FROM DUAL UNION ALL
SELECT 111, 'Mon', NULL FROM DUAL;
两个输出:
EMPID EMP 名称 小BOSS 小老板姓名 老大 老板姓名 100 莎拉 110 罗斯 111 周一 102 亚历克斯 110 罗斯 111 周一 101 本 111 周一 110 罗斯 111 周一 111 周一
db<>小提琴这里
MDO 的答案的简短版本是 -
WITH DATA AS (SELECT 100 AS empID, 'Sara' AS empName, 110 AS managerID FROM DUAL UNION ALL
SELECT 101, 'Ben', 111 FROM DUAL UNION ALL
SELECT 102, 'Alex', 110 FROM DUAL UNION ALL
SELECT 110, 'Ross', 111 FROM DUAL UNION ALL
SELECT 111, 'Mon', NULL FROM DUAL)
SELECT empID emp, empName, prior empID subBoss, prior empName subBossName
, prior t.managerID Boss
,CASE WHEN PRIOR t.managerID IS NOT NULL THEN CONNECT_BY_ROOT(t.empName) END AS BossName
FROM DATA T
START WITH managerID IS NULL
CONNECT BY PRIOR empID = managerID
ORDER BY 1;
请找到这个
带有 as (
选择 empID emp,empName empName,之前的 empID subBoss,之前的 empName subBossName,之前的经理 ID Boss
来自雇员
以 managerID 为空开始
通过先前的 empID = managerID 连接
排序依据 1)
选择a.*,b.empName BossName
从一个
左连接 emp b
在 a.boss = b.empID
按 1 排序;