如何让经理活跃的后代计数

时间:2017-05-14 06:20:28

标签: sql tsql

我需要创建一个查询,在查询管理器的层次结构下显示Employee,Manager,Active和活动后代。有人可以帮我吗?

结果:

/* EmployeeId   ManagerId   IsActive    NoofDescendantsActive
    1           -1       0              4                   
    2            1       1              3
    3            1       0              2
    4            2       1              2
    6            2       0              0
    7            3       1              0
    8            3       1              0
    9            4       1              1
    10           9       1              0
    11           9       0              0

* /

create table Person
(
    EmployeeId int,
    ManagerId int,
    IsActive bit
);

insert into Person(EmployeeId,ManagerId,IsActive) values
(1, -1, 0),
(2, 1, 1),
(3, 1, 0),
(4, 2, 1),
(6, 2, 0),
(7, 3, 1),
(8, 3, 1),
(9, 4, 1),
(10, 9, 1),
(11, 9, 0);

2 个答案:

答案 0 :(得分:2)

我认为您可以使用以下递归CTE 获得所需的结果:

;WITH Descendants_CTE AS (
    -- Anchor member: Get leaf nodes first
    SELECT p1.EmployeeId, p1.ManagerId, p1.IsActive, 0 AS level
    FROM Person AS p1
    WHERE NOT EXISTS (SELECT 1
                      FROM Person AS p2
                      WHERE p2.ManagerId = p1.EmployeeId)

    UNION ALL

    -- Recursive member: Get nodes of next level, keep track of
    -- the number of active nodes so far
    SELECT p.EmployeeId, p.ManagerId, p.IsActive, level = level + 1
    FROM Person AS p
    INNER JOIN Descendants_CTE AS d ON p.EmployeeId = d.ManagerId
    WHERE d.IsActive = 1        
)
SELECT EmployeeId, SUM(level) AS NoofDescendantsActive
FROM Descendants_CTE
WHERE level > 0
GROUP BY EmployeeId

递归遍历树“自下而上”,累计到目前为止遇到的“活动”节点的数量。如果满足非活动节点,则终止遍历。使用GROUP BY,我们可以获得每个非叶节点下的活动节点总数。如果您还想获得其他字段,则必须JOIN以上查询原始表格。

提示:为了更好地理解查询算法的实际效果,您可以在一张纸上构建树的图形。使用彩色标记突出显示每个活动节点。

Demo here

答案 1 :(得分:2)

Giorgos的solution有一个缺陷。如果员工#6是made active,则经理#1应该仅增加1。但是,在他的解决方案中,它增加了2。

EmployeeId  NoofDescendantsActive
1           6
2           4
3           2
4           2
9           1

这是一个有效的解决方案:

with Managers as
(
    select 
        RootManagerId = EmployeeId, IsActive
    from dbo.Person
    where EmployeeId in (select ManagerId from dbo.Person where IsActive = 1)    
),
A as -- Manager with employees
(
    select m.RootManagerId, AnchorManagerId = m.RootManagerId, 
           ManagerId = convert(int, null)
    from Managers m

    union all

    select m.RootManagerId, AnchorManagerId = d.EmployeeId, 
           d.ManagerId
    from A m
    -- collect descendants
    join dbo.Person d on m.AnchorManagerId = d.ManagerId and d.IsActive = 1
),
Solution as
(
    select RootManagerId, count(*) as Descendants
    from A
    where ManagerId is not null
    group by RootManagerId
)
-- select * from A order by RootManagerId; -- Uncomment to see how things works
select * from Solution;

Result

RootManagerId   Descendants
1               4
2               3
3               2
4               2
9               1

如果员工#6处于活动状态,则为result

RootManagerId   Descendants
1               5
2               4
3               2
4               2
9               1