SQL child parent 层次结构 - 使用 child 上的 where 隐藏 parent

SQL child parent hierarchy - Using a where on child to hide parent

假设我下面有 table:

ID | Name | Active | ParentID 
1  | Foo1 | 1      | 0
2  | Foo2 | 1      | 1 
3  | Foo3 | 1      | 2
4  | Foo4 | 1      | 3
5  | Foo5 | 1      | 3
6  | Foo6 | 0      | 5
7  | Foo7 | 1      | 2
7  | Foo7 | 1      | 6
8  | Foo8 | 1      | 7
9  | Foo9 | 1      | 5

(我确实有重复的ID,我表达了我的想法但没有结果)

如你所见,一次child可以有多个parent。 ParentID 为 0 的 ID 没有 parent。我需要 select 所有活动的 ID,并且在它们之上没有不活动的 parent,无论在树中可能有多高。

所以根据上面的数据集,我的结果是:

ID | Name | 
1  | Foo1 |
2  | Foo2 | 
3  | Foo3 |
4  | Foo4 |
5  | Foo5 |
9  | Foo9 |

我尝试在 where

中使用子查询
SELECT *
FROM table
WHERE ID not in (SELECT ID FROM table where Active = 0)

但这只能解决当前记录。

我也尝试过用于 employee/manager 的典型 self-join,但它只深入一层,而在这里我还需要检查 parent parent等

任何suggestions/ideas?

一种方法是使用 rCTE 处理层次结构,其中一列保留初始 ID。然后您可以使用 EXISTS 来确保 Active:

没有值为 0 的行
WITH rCTE AS(
    SELECT ID,
           Name,
           Active,
           ParentID,
           ID AS InitialID
    FROM dbo.YourTable YT
    UNION ALL
    SELECT YT.ID,
           YT.Name,
           YT.Active,
           YT.ParentID,
           r.InitialID
    FROM rCTE r
         JOIN dbo.YourTable YT ON r.ParentID = YT.ID)
SELECT *
FROM dbo.YourTable YT
WHERE NOT EXISTS (SELECT 1
                  FROM rCTE r
                  WHERE r.InitialID = YT.ID
                    AND r.Active = 0);

我会使用递归 CTE 来识别链是连续的 ID,使用条件和无条件递增 1,如下所示:

With A As 
(Select ID, [Name], Active, ParentID, 0 As NUM_1, 0 As NUM_2
 From Tbl Where ParentID=0
 Union All 
 Select Tbl.ID, Tbl.[Name], Tbl.Active, Tbl.ParentID,
        NUM_1 + 1 As NUM_1,
        NUM_2 + IIF(Tbl.Active=1,1,0) As NUM_2
 From Tbl Inner Join A On (Tbl.ParentID=A.ID)
)
Select ID, [Name]
From A
Where ID Not In (Select ID From A Where NUM_1<>NUM_2)
Order by ID

结果:

ID Name
1 Foo1
2 Foo2
3 Foo3
4 Foo4
5 Foo5
9 Foo9

db<>fiddle