(转)父子节点遍历

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://qianzhang.blog.51cto.com/317608/1205679

对于树/图的遍历,通常有2种算法来实现:迭代(Iteration)和递归(Recursion),迭代就是利用循环反复取值/赋值的过程;递归则是反复自己调用自己来获得最终结果。

不过SQL Server里的递归有32层嵌套限制,目的在于防止代码进入死循环。除非使用提示OPTION (MAXRECURSION 0)

测试数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if OBJECT_ID( 'city' is  not  null
     drop  table  city
GO
create  table  city
(
id     int ,
name   nvarchar(10),
pid    int ,
depth  int
)
GO
insert  into  city
select   1,N '江苏省' ,0,0  union  all
select   2,N '南京市' ,1,1  union  all
select   3,N '玄武区' ,2,2  union  all
select   4,N '鼓楼区' ,2,2  union  all
select   5,N '浙江省' ,0,0  union  all
select   6,N '杭州市' ,5,1  union  all
select   7,N '西湖区' ,6,2  union  all
select   8,N '滨江区' ,6,2  union  all
select   9,N '苏州市' ,1,1  union  all
select  10,N '吴中区' ,9,2  union  all
select  11,N '吴江区' ,9,2

 

一. 查找子节点

查找节点1的所有子节点,返回结果如下:

idnamepiddepth
1江苏省00
2南京市11
3玄武区22
4鼓楼区22
9苏州市11
10吴中区92
11吴江区92

 

1. 迭代

(1) 不借助depth,通过not in来向下查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if OBJECT_ID( 'f_get_child' is  not  null
     drop  function  f_get_child
GO
create  function  f_get_child
(
@id  int
)
returns  @t  table (id  int )
as
begin
     insert  into  @t  select  @id
     --insert into @t select id from city where pid = @id
     while @@ROWCOUNT>0
     begin
         insert  into  @t
         select  a.id
         from  city a  inner  join  @t b  on  a.pid = b.id
         where  a.id  not  in ( select  id  from  @t)
     end
     return
end
GO
select  from  city  where  id  in ( select  id  from  f_get_child(1))

 

(2) 通过depth来逐层查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if OBJECT_ID( 'f_get_child' is  not  null
     drop  function  f_get_child
GO
create  function  f_get_child
(
@id  int
)
returns  @t  table (id  int , depth  int )
begin
     declare  @depth  int
     set  @depth = 0
     insert  @t  select  ID,@depth  from  city  where  ID =@ID
     while @@ROWCOUNT>0
     begin
         set  @depth = @depth + 1
         insert  @t  select  a.ID,@depth
           from  city a, @t b
          where  a.pid = b.ID
            and  b.depth = @depth - 1
     end
     return 
end
GO
select  from  city  where  id  in ( select  id  from  f_get_child(1))

 

2. 递归

(1) 自定义函数递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
if OBJECT_ID( 'f_get_child' is  not  null
     drop  function  f_get_child
GO
create  function  f_get_child
(
@id  int
)
returns  @t  table (id  int )
as
begin
     declare  @pid  int
     set  @pid =  null
     insert  into  @t
     select  @id
     union  all
     select  id  from  city  where  pid = @id
                                                                      
     if exists( select  1
         from  city a  inner  join  @t b  on  a.pid = b.id
         where  a.id  not  in ( select  id  from  @t))
     begin
         insert  into  @t
         select  a.id
         from  city a  inner  join  @t b  on  a.pid = b.id
         where  a.id  not  in ( select  id  from  @t)
         union  all
         select  from  f_get_child(@pid)
     end
     return
end
GO
select  from  city  where  id  in ( select  from  f_get_child(1))

 

(2) CTE递归

1
2
3
4
5
6
7
8
9
10
11
12
declare  @id  int
set  @id = 1;
with  tmp
as
(
select  from  city  where  id = @id
union  all
select  a.*  from  city a
inner  join  tmp b
on  a.pid = b.id
)
select  from  tmp  order  by  id

 

二. 查找父节点

查找节点8的所有父节点,返回结果如下:

idnamepiddepth
5浙江省00
6杭州市51
8滨江区62

 

1. 迭代

父节点只有一个,不需要做什么限制,一直往上级查找pid就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if OBJECT_ID( 'f_get_parent' is  not  null
     drop  function  f_get_parent
GO
create  function  f_get_parent
(
@id  int
)
returns  @t  table (id  int )
as
begin
     declare  @pid  int
     insert  into  @t  select  @id
     select  @pid = pid  from  city  where  id = @id
     while @pid<>0
     begin
         insert  into  @t  values (@pid)
         select  @pid=pid  from  city  where  id=@pid
     end
     return
end
GO
select  from  city  where  id  in ( select  from  f_get_parent(8))

 

2. 递归

(1) 自定义函数递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if OBJECT_ID( 'f_get_parent' is  not  null
     drop  function  f_get_parent
GO
create  function  f_get_parent(@id  int )
returns  @t  table (id  int )
AS
begin
     declare  @pid  int
     select  top  1 @pid = pid
     from  city
     where  id = @id
     if @pid <> 0
     begin
         insert  into  @t
         select  @id
         union  all
         select  from  f_get_parent(@pid)
     end
     else
     begin
         insert  into  @t
         select  @id
     end
     return
end
GO
select  from  city  where  id  in ( select  from  f_get_parent(8))

 

(2) CTE递归

1
2
3
4
5
6
7
8
9
10
11
12
declare  @id  int
set  @id = 8;
with  tmp
as
(
select  from  city  where  id = @id
union  all
select  a.*  from  city a
inner  join  tmp b
on  a.id = b.pid
)
select  from  tmp  order  by  id

转载于:https://www.cnblogs.com/Luouy/p/3173989.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值