SQL CTE在层次结构中查找高级经理(自上而下的第二级)

时间:2018-10-29 14:47:58

标签: sql sql-server recursion common-table-expression

我有一个Employee IDs表和相应的Manager IDs,如下所示:

所需结果:高级经理专栏。该专栏的汇总经理可以直接向约翰·史密斯(EmpID: 1)或安娜·怀特(EmpID: 2)汇报。

示例:汤姆向杰克报告,蒂姆向安娜报告。

因此,杰克·布莱克的高级经理是蒂姆·史密斯(4

汤姆->杰克-> 蒂姆->安娜

enter image description here

我已经处理过CTE,但是查询返回了很多重复的行。否则,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会返回重复的行?

以下是示例数据:

 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);

2 个答案:

答案 0 :(得分:1)

您可以尝试添加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

sqlfiddle

结果

mpID    FirstName   LastName    
1       John        Smith       
2       Anna        White       

答案 1 :(得分:-2)

经过大量的故障排除后,我找到了解决方案。希望这会帮助需要帮助的人:)

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个人互相作为管理员,所以我不得不将它们排除在外。

  • 为每个重复的EmpID选择最后一行。由于某种原因,CTE每个EmpID都有2条记录,第一条记录包含top-level manager,第二行包含second-level manager。因此,我需要选择第二行。

编辑:

我的OP声明该代码已经给了我想要的输出,除了它陷入无限循环。那是我的主要问题,在排除了第一批雇员之后,问题得到解决。

我正在处理公司数据,该公司数据比显示的示例数据复杂得多,我无法在此处复制它或修复数据。如果有人遇到类似的问题,我不知道是否能为您提供确切的解决方案,但希望我提供的代码足以入门。

为什么我回答了自己的问题却接受了别人的回答:我的回答非常特定于数据库。它已经解决了这个特定问题,但我认为这不是最好的方法。我接受的答案更好。