Sql 二叉树得到最左或最右的底部

Sql 二叉树得到最左或最右的底部,sql,sql-server,binary-tree,Sql,Sql Server,Binary Tree,我有一个存储二叉树的表,如下所示: Id ParentId Level Placement 47 -1 0 0 23 47 1 0 86 47 1 1 5 23 2 0 29 23 2 1 68 86 2 0 8 5 3 1 31 29 3 1 67 68 3 0 . . .

我有一个存储二叉树的表,如下所示:

Id  ParentId Level Placement 
47   -1       0     0
23   47       1     0
86   47       1     1
5    23       2     0
29    23      2     1
68    86      2     0
8    5      3     1
31    29      3     1
67    68      3     0
.
.
.
使用MSSQL 现在,我需要得到给定id的左下角,在这个例子中,47的左下角是5 我需要得到给定id的右下角,在这个例子中,47的右下角是86

左下角或右下角不是左下角或右下角的最低层,而是左下角或右下角的最外层

如何编写为给定Id提供左下角或右下角的sql?

以上位置0为左,1为右


注意:注释掉最后一个where,以说明完整的层次结构

创建演示表

Declare @YourTable table (Id int,Pt int, Level int, Placement int) 
Insert Into @YourTable values 
(47,-1, 0,0),
(23,47, 1,0),
(86,47, 1,1),
(5 ,23, 2,0),
(29,23, 2,1),
(68,86, 2,0),
(8 , 5, 3,1),
(31,29, 3,1),
(67,68, 3,0)

SQL-

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

;with cteHB (Seq,ID,Pt,Lvl,Title,Placement) as (
    Select  Seq  = cast(1000+Row_Number() over (Order by ID) as varchar(500))
           ,ID   
           ,Pt   
           ,Lvl=1
           ,Title =concat('Item ',ID)
           ,Placement 
     From   @YourTable Where (Pt=-1 and isnull(@Top,-1) =-1) or (ID=@Top and isnull(@Top,0) <>0)
     Union  All
     Select Seq  = cast(concat(cteHB.Seq,'.',1000+Row_Number() over (Order by cteCD.ID)) as varchar(500))
           ,cteCD.ID 
           ,cteCD.Pt
           ,cteHB.Lvl+1
           ,Title = concat('Item ',cteCD.ID) 
           ,cteCD.Placement
     From   @YourTable cteCD 
     Join   cteHB on cteCD.Pt = cteHB.ID and cteHB.Lvl+1<=@MaxLvl and cteCD.Placement=0)

,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.Pt
      ,A.Lvl
      ,Title = Replicate(@Nest,A.Lvl) + A.Title
      ,A.Placement
 From cteHB A
 Join cteR1 B on A.ID=B.ID
 Join cteR2 C on A.ID=C.ID
 --Where R1=R2 
 Order By B.R1              

您应该使用递归查询

下面是最左侧查询的示例,您可以通过将位置更改为1轻松地将其更改为最右侧查询

with leftmost(ParentId,Id,depth) as (
    select t.Id,t.Id,0
    from #BinaryTree t
    union all
    select lm.parentid,t.Id,lm.depth+1
    from leftmost lm
        join #BinaryTree t on lm.Id = t.ParentId
    where t.Placement = 0 -- change to 1 for right most
)
select top 1 Id
from leftmost
where parentid = 47 --replace with the id you query
order by depth desc

我很难理解为什么8不是左下角,62不是右下角。如果99存在,它会是右下角吗?如果6存在,它会是左下角吗?我在数据中看不到有左有右。。。。或者仅仅使用最小/最大值就可以在ID上工作?@xQbert要获得47的左下角,您必须只遍历您的左孩子,而不要遍历右侧的ID。对了,我现在明白了。位置0表示左1表示右。我希望我的输出为5,而不是搜索底部时的所有这些详细信息left@JustinHomes修改sql以包含“和cteCD.Placement=0”,其中输入的是Id?因为一个表可以有多个这样的二叉树,即使对于这棵树,如果我给子节点29,它应该给右下角40,左下角29itself@JustinHomes当我使用parm Declare side int=0时,设置top--Declare[at]top int=null;声明searchId INT=47;与literalit的SQL-SERVER优化相比,这似乎运行得非常慢。您可以尝试选项(重新编译)
with leftmost(ParentId,Id,depth) as (
    select t.Id,t.Id,0
    from #BinaryTree t
    union all
    select lm.parentid,t.Id,lm.depth+1
    from leftmost lm
        join #BinaryTree t on lm.Id = t.ParentId
    where t.Placement = 0 -- change to 1 for right most
)
select top 1 Id
from leftmost
where parentid = 47 --replace with the id you query
order by depth desc