排序记录,因此 children 出现在 multi-level 层次结构中的 parent 之后

Order records so children appear just after parent in a multi-level hierarchy

我有一个 table 项目,其中包含 multi-level 层次结构的所有记录。因此,有一个顶级项目,它下面有项目,而它下面又有项目,依此类推;此外,此 table.

中将有许多顶级项目

我的目标是 return 来自这个 table 的记录,这样每个 parent 后面都有其 children 的记录(这些 children 可以是以任何顺序),然​​后每个 children 紧随其后的是它的 children(这些 children 可以按任何顺序),依此类推。我为此创建了一个 SQLFiddle:SQLFiddle for this

我尝试使用以下查询获取此信息,但第三级层次结构项目并没有出现在它们的 parent 之后。

select Id, ParentId, ChildLevel, 
CASE WHEN ChildLevel = 0 THEN Id 
     WHEN ChildLevel = 1 then Id  
     WHEN ChildLevel >  1 THEN ParentId END Num
from Items order by UltimateParentId, ChildLevel, Num ;

问题

有没有办法让 children 出现在 sql fiddle 上面的 parent 之后?

使用数据创建此 table 的脚本如下。

create table Items ( Id int , ParentId int , ChildLevel int,     UltimateParentId int);

--I could have multiple hierarchy level for each top level item
--right now I am populating data at multiple levels for only one top level item
--but the table will consist of many top level items having their own hierarchy records

insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (1,0,0,0);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (2,1,1,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (3,1,1,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (4,1,1,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (5,3,2,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (7,2,2,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (6,3,2,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (8,4,2,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (9,3,2,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (10,2,2,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (11,4,2,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (12,11,3,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (13,5,3,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (14,11,3,1);
insert into Items (Id, ParentId, ChildLevel, UltimateParentId) values (15,5,3,1);

是的。 通用 Table 表达式 (CTE) 可以递归。如果您使用 CTE,您只需要父级 IS。查看 https://technet.microsoft.com/pl-pl/library/ms186243(v=sql.105).aspx

由于您没有为 ID/Parent 使用字符串,您可以利用 hierarchyid 数据类型。

R1,R2 和 HierPath 在最后 select 是可选的。 R1 和 R2 表示所有权范围。这有助于聚合和 selection 而无需递归。

例子

;with cteP as (
      Select ID
            ,ParentId 
            ,HierID = convert(hierarchyid,concat('/',ID,'/'))
      From   Items 
      Where  ParentId=0
      Union  All
      Select ID  = r.ID
            ,ParentId  = r.ParentId 
            ,HierID = convert(hierarchyid,concat(p.HierID.ToString(),r.ID,'/'))
      From   Items r
      Join   cteP p on r.ParentId  = p.ID)
Select R1    = Row_Number() over (Order By HierID)
      ,R2    = Row_Number() over (Order By HierID) + -1 + (Select count(*) From cteP where HierID.ToString() like A.HierID.ToString()+'%')
      ,Lvl   = HierID.GetLevel()
      ,ID
      ,ParentId
      ,HierID
      ,HierPath = HierID.GetDescendant ( null , null ).ToString()   
 From cteP A
 Order By A.HierID

Returns

根据要求。以下可以在几秒钟内生成 200K 层

I should add... Where you see Row_Number() over (Order By ID) I used ID, but this can be any other field to determine the desired presentation sequence.

例子

Select *,Lvl=1,Seq=cast(1000000+Row_Number() over (Order By ID) as varchar(900)) Into #TempBld from Items Where  ParentID = 0

Declare @Cnt int=1
While @Cnt<=30
    Begin
        Insert Into #TempBld 
        Select A.*,Lvl=B.Lvl+1,Seq=B.Seq+' '+ cast(1000000+Row_Number() over (Order By A.ID) as varchar(25))
         From  Items A
         Join  #TempBld B on (B.Lvl=@Cnt and A.ParentID=B.ID)
        Set @Cnt=@Cnt+1
    End

Select ID,R1=cast(Row_Number() over (Order by Seq) as int),Seq Into #TempR1 From #TempBld
Create Clustered Index idx on #TempR1 (Seq)
Select A.ID,R2 = Max(B.R1) Into  #TempR2 From  #TempBld A Join #TempR1  B on B.Seq Like A.Seq+'%' Group By A.ID

Select B.R1
      ,C.R2
      ,A.Lvl 
      ,A.ID
      ,A.ParentID
 From  #TempBld A
 Join  #TempR1  B on (A.ID=B.ID)
 Join  #TempR2  C on (A.ID=C.ID)
 Order By 1

Returns