我有以下表格架构:
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, E
和F
。
当我E
时,我想获得E
和F
。
当我D
时,我想获得D, E
和F
。
我不是SQL专家,作为开发人员,我通常会使用DB查询以编程方式构建循环,并检查我是否有孩子并递归获取子项。但这绝对是一种非常昂贵/无法实现的方法。
使用SQL语句是否有优雅/更好的方法?
答案 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