在单个表中使用id parentid关系时,如何在SQL表中使用所有可能的子行

时间:2016-08-25 12:23:32

标签: sql sql-server tsql

我有以下表格架构:

ID | PARENT ID | NAME
-------------------------
1  | NULL      | A - ROOT
2  | 1         | B
3  | 2         | C
4  | 1         | D
5  | 4         | E
6  | 5         | F 

层次结构如下:

   A
   -- B
   -- -- C
   -- D
   -- -- E
   -- -- -- F

我希望在所有后代级别中递归所有孩子。

例如,当我有A并对其进行查询时,我想返回A, B, C, D, EF

当我E时,我想获得EF

当我D时,我想获得D, EF

我不是SQL专家,作为开发人员,我通常会使用DB查询以编程方式构建循环,并检查我是否有孩子并递归获取子项。但这绝对是一种非常昂贵/无法实现的方法。

使用SQL语句是否有优雅/更好的方法?

3 个答案:

答案 0 :(得分:1)

这是一个通用的层次结构构建。这个将保持演示顺序,还包括RANGE KEYS(可选,如果不需要,可以轻松删除)

Declare @YourTable table (ID int,Parent_ID int,Name varchar(50))
Insert into @YourTable values (1,null,'A - Root'),(2,1,'B'),(3,2,'C'),(4,1,'D'),(5,4,'E'),(6,5,'F')


Declare @Top  int = null          --<<  Sets top of Hier Try 4
Declare @Nest varchar(25) ='   '  --<<  Optional: Added for readability

;with cteHB (Seq,ID,Parent_ID,Lvl,Name) as (
    Select  Seq  = cast(1000+Row_Number() over (Order by Name) as varchar(500))
           ,ID
           ,Parent_ID
           ,Lvl=1
           ,Name 
     From   @YourTable 
     Where  IsNull(@Top,-1) = case when @Top is null then isnull(Parent_ID,-1) else ID end
     Union  All
     Select Seq  = cast(concat(cteHB.Seq,'.',1000+Row_Number() over (Order by cteCD.Name)) as varchar(500))
           ,cteCD.ID
           ,cteCD.Parent_ID,cteHB.Lvl+1
           ,cteCD.Name 
     From   @YourTable cteCD 
     Join   cteHB on cteCD.Parent_ID = cteHB.ID)
    ,cteR1 as (Select Seq,ID,R1=Row_Number() over (Order By Seq) From cteHB)
    ,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
Select B.R1  
      ,C.R2
      ,A.ID
      ,A.Parent_ID
      ,A.Lvl
      ,Name = Replicate(@Nest,A.Lvl) + A.Name
 From cteHB A
 Join cteR1 B on A.ID=B.ID
 Join cteR2 C on A.ID=C.ID
 Order By B.R1              --<< Or use A.Seq

返回

R1  R2  ID  Parent_ID   Lvl    Name
1   6   1   NULL        1      A - Root
2   3   2   1           2         B
3   3   3   2           3            C
4   6   4   1           2         D
5   6   5   4           3            E
6   6   6   5           4               F

答案 1 :(得分:1)

您可以使用以下公用表表达式:

;with cte as 
(
select id, name from hierarchy where parentid is null

union all

select h.id, h.name from hierarchy h inner join cte c
on h.parentid = c.id
)
select * from cte

答案 2 :(得分:1)

这将为您提供所需的结果:

DECLARE @search nvarchar(1) = 'D'

;WITH cte AS (
SELECT  ID,
        [PARENT ID],
        NAME
FROM YourTable
WHERE NAME = @search
UNION ALL
SELECT  y.ID,
        y.[PARENT ID],
        y.NAME
FROM YourTable y
INNER JOIN cte c
    ON y.[PARENT ID] = c.ID
)

SELECT *
FROM cte
ORDER BY NAME