递归地获取具有haschildren标识符的层次结构中的子项

时间:2017-01-19 21:52:34

标签: sql sql-server

我的问题是如何标记返回行中的标识符,该标识符将告诉我返回的row.id是否有更多子项

Sample Data
id  parenId Name parentName 
9   8        nine   eight
8   7        eight  seven
6   8        six    eight
5   8        five   eight
4   8        four   eight
3   8        three  eight
2   1        two    one
1   1        one    one
12  7        tweleve  seven
11  12      eleven  twelve

如果我在下面的查询中传递了parentId为7,则返回

8   7 eight
6   8   six
5   8   five
4   8 four
3   8 three
12  7   tweleve
11  12  eleven

但我想要的是id为更多的孩子被标记为例如8和12有更多的孩子

8   7 eight   haschidlren
6   8   six
5   8   five
4   8 four
3   8 three
12  7   tweleve   haschidlren
11  12  eleven

WITH name_tree
     AS (SELECT Id,
                Parentid,
                Name,
                ParentName
         FROM   TableWithHiearchy
         WHERE  Parentid = 7
         -- this is the starting point you want in your recursion
         UNION ALL
         SELECT c.Id,
                c.Parentid,
                c.Name,
                ParentName
         FROM   TableWithHiearchy c
                JOIN name_tree p
                  ON p.Id = c.ParentId -- this is the recursion
                     AND c.Id <> c.Parentid

                     )
SELECT distinct Id, parenId, Name 

FROM   name_tree 

2 个答案:

答案 0 :(得分:0)

我只想在case when exists (id is parent) then true else false end

的查询中添加一列

rextester链接:http://rextester.com/RAU96705

create table TableWithHiearchy (
    id int
  , parentid int
  , name varchar(32)
  , parentname varchar(32)
)
insert into TableWithHiearchy values 
(9,8,'nine','eight')
,(8,7,'eight','seven')
,(6,8,'six','eight')
,(5,8,'five','eight')
,(4,8,'four','eight')
,(3,8,'three','eight')
,(2,1,'two','one')
,(1,1,'one','one')
,(12,7,'tweleve','seven')
,(11,12,'eleven','twelve');

with name_tree as (
  select 
        Id
      , Parentid
      , Name
      , ParentName
      , [Path]=convert(varchar(64), 
                isnull(convert(varchar(10),ParentId) + '.','') 
                + convert(varchar(10),Id)
                 )
    from   TableWithHiearchy
    where  ParentId = 7
    -- this is the starting point you want in your recursion
    union all
    select 
          c.Id
        , c.Parentid
        , c.Name
        , c.ParentName --=p.Name
        , Path=convert(varchar(64),p.Path + '.' + convert(varchar(10),c.Id))
      from   TableWithHiearchy c
        join name_tree p
          on p.Id = c.ParentId -- this is the recursion
            and c.Id <> c.Parentid
)
select distinct Id, parentId, Name, Path
  , HasChildren= case 
      when exists (
          select 1 
            from name_tree i
            where i.parentid=o.id
            ) 
      then 'HasChildren'
      else '' 
      end
from   name_tree o

结果

+----+----------+---------+---------+-------------+
| Id | parentId |  Name   |  Path   | HasChildren |
+----+----------+---------+---------+-------------+
|  3 |        8 | three   | 7.8.3   |             |
|  4 |        8 | four    | 7.8.4   |             |
|  5 |        8 | five    | 7.8.5   |             |
|  6 |        8 | six     | 7.8.6   |             |
|  8 |        7 | eight   | 7.8     | HasChildren |
|  9 |        8 | nine    | 7.8.9   |             |
| 11 |       12 | eleven  | 7.12.11 |             |
| 12 |        7 | tweleve | 7.12    | HasChildren |
+----+----------+---------+---------+-------------+

我添加了路径,所以我可以直接看到。

答案 1 :(得分:0)

这是另一种选择。

在cte0中,我们将您的表标准化(请记住将@YourTable替换为您的实际表名。

在cteP中,我们构建了您的层次结构。

@Top 设置为 NULL 时,您将获得整个层次结构,否则请指定所需的顶级ID。

可以轻松地将TVT或存储过程作为参数传递给@Top

Declare @YourTable table (id int,parentId int,Name varchar(25),parentName varchar(25))
Insert Into @YourTable values
(9,   8, 'nine'   ,'eight'),
(8,   7, 'eight'  ,'seven'),
(6,   8, 'six'    ,'eight'),
(5,   8, 'five'   ,'eight'),
(4,   8, 'four'   ,'eight'),
(3,   8, 'three'  ,'eight'),
(2,   1, 'two'    ,'one'),
(1,   1, 'one'    ,'one'),
(12,  7, 'tweleve','seven'),
(11,  12,'eleven' ,'twelve')

Declare @Top  int         = null      --<<  Sets top of Hier Try 8 or 12
Declare @Nest varchar(25) = '|-----'  --<<  Optional: Added for readability

;with cte0 as (
      Select Distinct ID,ParentID,Name From @YourTable
      Union All 
      Select Distinct ID=parentID,ParentID=NULL,Name=parentName From @YourTable where ParentID not in (Select Distinct ID From @YourTable) ),
      cteP as (
      Select Distinct
             Seq  = cast(10000+Row_Number() over (Order by ID) as varchar(500))
            ,ID
            ,parentId
            ,Name
            ,Lvl=1
      From   cte0 
      Where  IsNull(@Top,-1) = case when @Top is null then isnull(parentId,-1) else ID end
      Union  All
      Select Seq  = cast(concat(p.Seq,'.',10000+Row_Number() over (Order by r.ID)) as varchar(500))
            ,r.ID
            ,r.parentId
            ,r.Name
            ,p.Lvl+1
      From   cte0 r
      Join   cteP p on r.parentId = p.ID and r.id<>r.parentId)
     ,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP )
     ,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 A.R1  
      ,B.R2
      ,A.ID
      ,A.parentId
      ,A.Lvl
      ,Title       = Replicate(@Nest,A.Lvl-1) + A.Name
      ,HasChildren = case when A.R1<>B.R2 then 'haschildren' else '' end
 From cteR1 A
 Join cteR2 B on A.ID=B.ID 
 Order By A.R1

<强>返回

enter image description here

现在,如果您将 @Top 设置为 8 ,您将获得

enter image description here