2017-05-14 16 views
0

従業員、マネージャ、アクティブ、アクティブな子孫をマネージャの階層の下に表示するクエリを作成する必要があります。誰もが私にこれを助けることができますか?マネージャのアクティブ子孫カウントの取得方法

結果:

/* 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); 
+0

ギブあなたの予想される出力 – Utsav

+1

@cris gomez - あなたはアクティブな子孫をどのように計算していますか?従業員ID#1にはアクティブな直接下位が1つありますが、アクティブな子孫は6つあります。どのように3を得るのだろうか? –

+0

ID#1階層の@DLは、ID#2(アクティブ)とID#6 ID#3はID#9(アクティブ)、ID#9はID#10(アクティブ)、ID#11(非アクティブ)です。アクティブな子孫を取得しているので、アクティブ・デカンタントは3つしかありません。ここにメッセージを送るだけで、もっと情報が必要な場合。ありがとう –

答えて

2

Giorgosのsolutionは欠陥を有しています。従業員#6がmade activeの場合、マネージャ#1は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だが、彼の溶液中で、それはここで機能するソリューションです。2.

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

増加しました:

RootManagerId Descendants 
1    5 
2    4 
3    2 
4    2 
9    1 
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する必要があります。

ヒント:クエリのアルゴリズムが実際にどのように機能するかを理解するために、1枚の紙面にツリーのグラフを作成することができます。色付きマーカーを使用して各アクティブノードをハイライト表示します。

Demo here

+0

ありがとうGiorgos Betsos。 :) –

+0

@crisgomezうれしい私は助けてくれました。あなたの問題を解決するのに役立ちましたら、これを記入してください。 –

関連する問題