在T-SQL中访问同一级别的父节点

时间:2012-10-16 07:37:12

标签: sql tsql

假设我有一个这样的数据库模式:

RowId   ParentId   Name
------ ---------- ------
1       NULL      Level1
2       NULL      Level2
3       1         Leaf1
4       1         Leaf2
5       2         Leaf1
6       3         LeafX

基本上,树看起来像这样:

Level1
       Leaf1
             LeafX
       Leaf2
Level2
       Leaf1

我需要以最有效和最动态的方式提取LeafX的所有祖先LEVEL。

因此它将输出:Leaf1,Leaf2和Leaf1(Level2)

如何在T-SQL中执行此操作?感谢

4 个答案:

答案 0 :(得分:3)

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

;with C as
(
  select T.rowid,
         T.parentid,
         T.name,
         1 as Lvl
  from YourTable as T
  where T.parentid is null
  union all
  select T.rowid,
         T.parentid,
         T.name,
         C.Lvl + 1
  from YourTable as T
    inner join C
       on T.parentid = C.rowid
)
select *
from C
where C.Lvl = (
               select C.lvl-1
               from C
               where C.name = 'LeafX'
              )

<强>更新
这对你来说可能更快。你必须测试你的数据。

declare @Level int;

with C as
(
  select T.rowid,
         T.parentid
  from @t as T
  where T.name = 'LeafX'
  union all
  select T.rowid,
         T.parentid
  from @t as T
    inner join C
       on T.rowid = C.parentid
)
select @Level = count(*) - 1
from C;

with C as
(
  select T.rowid,
         T.parentid,
         T.name,
         1 as Lvl
  from @t as T
  where T.parentid is null
  union all
  select T.rowid,
         T.parentid,
         T.name,
         C.Lvl + 1
  from @t as T
    inner join C
       on T.parentid = C.rowid
  where C.Lvl < @Level
)
select *
from C
where C.Lvl = @Level;

答案 1 :(得分:1)

有几种方法可以做到这一点。我最喜欢的是创建特殊的表Trees_Parents,在那里你将存储每个父节点的evere节点。 所以,如果有这样的结构

RowId   ParentId   Name
------ ---------- ------
1       NULL      Level1
2       NULL      Level2
3       1         Leaf1
4       1         Leaf2
5       2         Leaf1
6       3         LeafX

你的Trees_Parents表看起来像

RowId   ParentId
------ ----------
1       1     
2       2     
3       3
3       1        
4       4
4       1        
5       5
5       2        
6       6
6       1
6       3        

然后当你需要检索所有孩子时,你只需要写

select RowID from Trees_Parents where ParentId = 1

我在这个表中存储行self以避免使用工会,如果你不需要它就可以编写

select RowID from Trees_Parents where ParentId = 1 and ParentId <> RowId

对于所有的父母,你会写

select ParentId from Trees_Parents where RowId = 6 and ParentId <> RowId

您还可以将Table_Name存储在表Trees_Parents中,以便将其用于不同的表

另一种方法是编写递归的WITH子句,但是如果你的树很大并且它没有经常更改,我认为最好将父数据存储在附加表中

答案 2 :(得分:1)

你可以使用递归解决方案。您需要获得所有节点的Depth =节点的深度 - 1

declare @Temp table (RowId int, ParentId int, Name nvarchar(128))

insert into @Temp
select 1, null, 'Level1' union all
select 2, null, 'Level2' union all
select 3, 1, 'Leaf1' union all
select 4, 1, 'Leaf2' union all
select 5, 2, 'Leaf3' union all
select 6, 3, 'LeafX';

with Parents
as
(
    select T.RowId, 0 as Depth from @Temp as T where T.ParentId is null
    union all
    select T.RowId, P.Depth + 1
    from Parents as P
        inner join @Temp as T on T.ParentId = P.RowId
)
select T.Name
from Parents as P
    outer apply (select TT.Depth from Parents as TT where TT.RowId = 6) as CALC
    left outer join @Temp as T on T.RowId = P.RowId
where P.Depth = CALC.Depth - 1

答案 3 :(得分:1)

declare @t table(rowid int, parentid int, name varchar(10))
insert @t values(1,NULL,'Level1')
insert @t values(2,NULL,'Level2')
insert @t values(3,1,'Leaf1')
insert @t values(4,1,'Leaf2')
insert @t values(5,2,'Leaf1')
insert @t values(6,3,'LeafX')

;with a as
(
select rowid, parentid, 0 level from @t where name = 'leafx'
union all
select t.rowid, t.parentid, level + 1 from @t t
join a on a.parentid = t.rowid
), b as
(
select rowid, parentid,name,  0 level from @t where parentid is null
union all
select t.rowid, t.parentid,t.name, level + 1 
from b join @t t on b.rowid = t.parentid
)
select rowid, parentid, name from b
where level = (select max(level)-1 from a)

rowid   parentid    name
5   2   Leaf1
3   1   Leaf1
4   1   Leaf2