Прежде всего, всегда старайтесь по возможности избегать циклов.
Ниже приведен пример использования рекурсивного CTE совместно с типом данных HIERARCHY.
Рекурсивные CTE великолепны, истоит потратить ваше время, чтобы освоиться с ними.Тем не менее, производительность может немного пострадать при больших / более глубоких иерархиях.
Существуют и другие методы, использующие таблицы TEMP, которые более производительны, но немного сложнее.
Пример
Declare @Top int = null --<< Sets top of Hier Just for FUN Try 3
;with cteP as (
Select ID
,ManagerID
,Name
,HierID = convert(hierarchyid,'/'+convert(varchar(25),ID)+'/')
From YourTable
Where IsNull(@Top,-1) = case when @Top is null then isnull(ManagerID ,-1) else ID end
Union All
Select ID = r.ID
,ManagerID = r.ManagerID
,Name = r.Name
,HierID = convert(hierarchyid,p.HierID.ToString()+convert(varchar(25),r.ID)+'/')
From YourTable r
Join cteP p on r.ManagerID = p.ID)
Select Lvl = HierID.GetLevel()
,ID
,Name
,ManagerID
From cteP A
Order By A.HierID
Возвращает
Lvl ID Name ManagerID
1 2 Alpha NULL
2 4 Bravo 2
3 1 Charlie 4
4 5 Delta 1
5 3 Echo 5
6 6 Foxtrot 3
7 7 Golf 6
8 8 Hotel 7
9 9 Juliet 8
9 10 India 8
РЕДАКТИРОВАТЬ - Temp Table Approach 25 000 строк за 2 секунды
Обратите внимание, что у меня максимальная глубина 30 уровней.
Declare @Top int =null
Select *
,Lvl=1
,HierID = convert(hierarchyid,'/'+convert(varchar(25),ID)+'/')
Into #TempBld
From YourTable
Where IsNull(@Top,-1) = case when @Top is null then isnull(ManagerID,-1) else ID end
Declare @Cnt int=1
While @Cnt<=30
Begin
Insert Into #TempBld
Select A.*
,Lvl=B.Lvl+1
,HierID = convert(hierarchyid,b.HierID.ToString()+convert(varchar(25),a.ID)+'/')
From YourTable A
Join #TempBld B on (B.Lvl=@Cnt and A.ManagerID=B.ID)
Set @Cnt=@Cnt+1
End
Select Lvl
,ID
,Name
,ManagerID
From #TempBld
Order by HierID