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 |
- ID 6 已被删除,因为它处于非活动状态
- ID 7 已被删除,因为它的 parents (6) 之一处于非活动状态
- ID 8 被删除,因为其 parent (7) 的 parent (6) 处于非活动状态
- ID 9 很好,因为它的 parent (5) 是活动的,5 他的 parents 等
我尝试在 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
假设我下面有 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 |
- ID 6 已被删除,因为它处于非活动状态
- ID 7 已被删除,因为它的 parents (6) 之一处于非活动状态
- ID 8 被删除,因为其 parent (7) 的 parent (6) 处于非活动状态
- ID 9 很好,因为它的 parent (5) 是活动的,5 他的 parents 等
我尝试在 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 |