SQL CTE 寻找层次结构中的高级经理(从上到下第 2 级)
SQL CTE to Find Senior Managers in Hierarchy (2nd Level from the Top)
我有一个Employee IDs
的table对应Manager IDs
,如下图:
期望的结果:高级经理专栏。,其中包含直接向 John Smith (EmpID: 1
) 或 Anna White (EmpID: 2
).
示例:Tom 向 Jack 汇报,Jack 向 Tim 汇报,Tim 向 Anna 汇报。
因此,Jack Black 的高级经理是 Tim Smith,4
。
汤姆 --> 杰克 --> 蒂姆 --> 安娜
我曾处理过 CTE
,但查询 return 有很多重复的行。否则,CTE
输出正确的数据。
WITH cte AS
(
SELECT EmpID, FirstName, LastName, EmpID as SeniorManager
FROM Employees
WHERE ManagerID < 3
AND EmpActive = 1
UNION ALL
SELECT emp.EmpID, emp.FirstName, emp.LastName, c.SeniorManager
FROM Employees emp
JOIN cte c ON c.EmpID = emp.ManagerID
WHERE emp.EmpID <> emp.ManagerID
AND emp.EmpActive = 1
)
SELECT * FROM cte
示例数据是公司数据库中实际数据的简化版本。我的主要问题:为什么 CTE return 重复行?
示例数据如下:
CREATE TABLE Employees (
EmpID INT NOT NULL PRIMARY KEY,
FirstName VARCHAR(35) NOT NULL,
LastName VARCHAR(35) NOT NULL,
ManagerID INT NOT NULL);
INSERT INTO Employees
(EmpID, FirstName, LastName, ManagerID)
VALUES
(1, 'John', 'Smith', 2),
(2, 'Anna', 'White', 1),
(3, 'Jack', 'Black', 4),
(4, 'Tim', 'Smith', 2),
(5, 'Jason', 'Black', 3),
(6, 'Tom', 'Black', 3);
您可以尝试添加一个 level
列来表示人员层次结构。
那就只有level = 1
个人了。
WITH cte AS
(
SELECT EmpID,FirstName,LastName,ManagerID,1 level
FROM Employees
UNION ALL
SELECT t2.EmpID,t2.FirstName,t2.LastName,t2.ManagerID,level+ 1
FROM cte t1 JOIN Employees t2
on t1.EmpId = t2.ManagerID
WHERE t1.ManagerID <> t2.EmpId
)
SELECT EmpID,FirstName,LastName
FROM cte t1
where not exists (
select 1
from cte tt
WHERE tt.level = 2 and t1.EmpID = tt.EmpID
) and level = 1
结果
mpID FirstName LastName
1 John Smith
2 Anna White
经过大量故障排除,我找到了解决方案。希望这会帮助有需要的人:)
WITH cte AS
(
SELECT EmpID, FirstName, LastName, EmpID as SeniorManager
FROM Employees
WHERE ManagerID <= 2
AND Active = 1
UNION ALL
SELECT e.EmpID, e.FirstName, e.LastName, c.SeniorManager
FROM tblEmployee e
JOIN cte c ON c.EmpID = e.ManagerID
WHERE e.EmpID <> e.ManagerID
AND e.EmpID >= 3
AND e.Active = 1
)
SELECT EmpID, FirstName, LastName, MAX(SeniorManager) SeniorManager FROM cte
GROUP BY EmpID, FirstName, LastName
解释:
在联接的第二部分添加了 e.EmpID > 3。重复的行是由于无限循环,因为有2个人互相作为经理,所以我不得不排除他们。
Select 每个重复项的最后一行 EmpID
。出于某种原因,cte 每个 EmpID
都有 2 条记录,第一行带有 top-level manager
,第二行带有 second-level manager
。因此,我需要 select 第二行。
编辑:
我的 OP 声明代码已经为我提供了我想要的输出,只是它遇到了无限循环。这是我的主要问题,在将第一批员工排除在外后解决了。
我正在处理比显示的示例数据复杂得多的公司数据,我无法在此处复制或修复数据。如果有人遇到类似的问题,我不知道我是否可以为您提供确切的解决方案,但希望我提供的代码足以让您入门。
为什么我回答了自己的问题却接受了别人的回答:我的回答是针对数据库的。它适用于这个特定问题,但我认为这不是最好的方法。我接受的答案更好。
WITH recursive cte
AS (
SELECT emp.*, 0 AS LEVEL, managerid AS supervisor
FROM employees emp
WHERE empid IN (1, 2)
UNION ALL
SELECT emp.*, cte.LEVEL + 1, CASE
WHEN cte.LEVEL IN (0, 1)
THEN emp.managerid
ELSE cte.supervisor
END
FROM employees emp, cte
WHERE cte.empid = emp.managerid
AND emp.empid NOT IN (1, 2)
)
SELECT * FROM cte
我有一个Employee IDs
的table对应Manager IDs
,如下图:
期望的结果:高级经理专栏。,其中包含直接向 John Smith (EmpID: 1
) 或 Anna White (EmpID: 2
).
示例:Tom 向 Jack 汇报,Jack 向 Tim 汇报,Tim 向 Anna 汇报。
因此,Jack Black 的高级经理是 Tim Smith,4
。
汤姆 --> 杰克 --> 蒂姆 --> 安娜
我曾处理过 CTE
,但查询 return 有很多重复的行。否则,CTE
输出正确的数据。
WITH cte AS
(
SELECT EmpID, FirstName, LastName, EmpID as SeniorManager
FROM Employees
WHERE ManagerID < 3
AND EmpActive = 1
UNION ALL
SELECT emp.EmpID, emp.FirstName, emp.LastName, c.SeniorManager
FROM Employees emp
JOIN cte c ON c.EmpID = emp.ManagerID
WHERE emp.EmpID <> emp.ManagerID
AND emp.EmpActive = 1
)
SELECT * FROM cte
示例数据是公司数据库中实际数据的简化版本。我的主要问题:为什么 CTE return 重复行?
示例数据如下:
CREATE TABLE Employees (
EmpID INT NOT NULL PRIMARY KEY,
FirstName VARCHAR(35) NOT NULL,
LastName VARCHAR(35) NOT NULL,
ManagerID INT NOT NULL);
INSERT INTO Employees
(EmpID, FirstName, LastName, ManagerID)
VALUES
(1, 'John', 'Smith', 2),
(2, 'Anna', 'White', 1),
(3, 'Jack', 'Black', 4),
(4, 'Tim', 'Smith', 2),
(5, 'Jason', 'Black', 3),
(6, 'Tom', 'Black', 3);
您可以尝试添加一个 level
列来表示人员层次结构。
那就只有level = 1
个人了。
WITH cte AS
(
SELECT EmpID,FirstName,LastName,ManagerID,1 level
FROM Employees
UNION ALL
SELECT t2.EmpID,t2.FirstName,t2.LastName,t2.ManagerID,level+ 1
FROM cte t1 JOIN Employees t2
on t1.EmpId = t2.ManagerID
WHERE t1.ManagerID <> t2.EmpId
)
SELECT EmpID,FirstName,LastName
FROM cte t1
where not exists (
select 1
from cte tt
WHERE tt.level = 2 and t1.EmpID = tt.EmpID
) and level = 1
结果
mpID FirstName LastName
1 John Smith
2 Anna White
经过大量故障排除,我找到了解决方案。希望这会帮助有需要的人:)
WITH cte AS
(
SELECT EmpID, FirstName, LastName, EmpID as SeniorManager
FROM Employees
WHERE ManagerID <= 2
AND Active = 1
UNION ALL
SELECT e.EmpID, e.FirstName, e.LastName, c.SeniorManager
FROM tblEmployee e
JOIN cte c ON c.EmpID = e.ManagerID
WHERE e.EmpID <> e.ManagerID
AND e.EmpID >= 3
AND e.Active = 1
)
SELECT EmpID, FirstName, LastName, MAX(SeniorManager) SeniorManager FROM cte
GROUP BY EmpID, FirstName, LastName
解释:
在联接的第二部分添加了 e.EmpID > 3。重复的行是由于无限循环,因为有2个人互相作为经理,所以我不得不排除他们。
Select 每个重复项的最后一行
EmpID
。出于某种原因,cte 每个EmpID
都有 2 条记录,第一行带有top-level manager
,第二行带有second-level manager
。因此,我需要 select 第二行。
编辑:
我的 OP 声明代码已经为我提供了我想要的输出,只是它遇到了无限循环。这是我的主要问题,在将第一批员工排除在外后解决了。
我正在处理比显示的示例数据复杂得多的公司数据,我无法在此处复制或修复数据。如果有人遇到类似的问题,我不知道我是否可以为您提供确切的解决方案,但希望我提供的代码足以让您入门。
为什么我回答了自己的问题却接受了别人的回答:我的回答是针对数据库的。它适用于这个特定问题,但我认为这不是最好的方法。我接受的答案更好。
WITH recursive cte
AS (
SELECT emp.*, 0 AS LEVEL, managerid AS supervisor
FROM employees emp
WHERE empid IN (1, 2)
UNION ALL
SELECT emp.*, cte.LEVEL + 1, CASE
WHEN cte.LEVEL IN (0, 1)
THEN emp.managerid
ELSE cte.supervisor
END
FROM employees emp, cte
WHERE cte.empid = emp.managerid
AND emp.empid NOT IN (1, 2)
)
SELECT * FROM cte