在一个表中,有这样的一个层级关系,ID为主键,PId为父级ID
关系如下图:
然后呢,现在的需求是,已知某一条记录的ID,求出它顶层父级的ID,也就是我们所谓的“寻根”计划。
这类问题解决方法很多,首先我用SQL中的函数来解决,许久不写,正好练习一下:
1 --创建函数 2 CREATE function F_FindPIdByID 3 ( 4 @ID varchar(15) --参数 5 ) 6 returns varchar(500) 7 as 8 begin 9 10 declare @PId varchar(15) --变量父级ID,当前ID的PID 11 declare @Place varchar(500) --变量Place,最终返回结果 12 set @Place = '0' 13 begin 14 --首先根据传入的ID获取其父ID,PID 15 SELECT @PId = PId FROM T_Recursion 16 where ID = @ID 17 end 18 19 if (@PId<> '0')--如果不是根节点 20 begin 21 -- 再将@PID 作为参数@ID传入函数进行自调用 22 set @Place =dbo.F_FindPIdByID(@PId); 23 end 24 else 25 begin 26 --满足PId=0这个条件,则把当前传入函数中的ID赋值并返回,即当前的PId就是最终要获取到的ID 27 set @Place =@ID 28 end 29 return @Place 30 end 31 go
函数创建好了(有点递归的味道)
下面给定参数,然后执行函数,看看结果
1 --测试A 2 select dbo.F_FindPIdByID(1111) as 'ID' 3 4 --测试B 5 select dbo.F_FindPIdByID(21) as 'ID' 6 7 --测试C 8 select dbo.F_FindPIdByID(31) as 'ID'
测试的结果



大功告成。
接下来,我们试试另一个方法。直接写查询语句来实现,这里要用到[ WITH AS ]。
什么是WITH AS?
1、WITH AS短语,也叫做子查询部分(subquery factoring),可以定义一个SQL片断,该SQL片断会被整个SQL语句用到。可以使SQL语句的可读性更高,也可以在UNION ALL的不同部分,作为提供数据的部分。
2、对于UNION ALL,使用WITH AS定义了一个UNION ALL语句,当该片断被调用2次以上,优化器会自动将该WITH AS短语所获取的数据放入一个Temp表中。而提示meterialize则是强制将WITH AS短语的数据放入一个全局临时表中。很多查询通过该方式都可以提高速度。
搞清楚什么是 with as,我们就来用一下,核心思想是ID作为PId条件找到上级ID
1 with Tree AS 2 ( 3 SELECT * FROM T_Recursion WHERE ID = 1111 4 UNION ALL 5 SELECT a.* FROM Tree , T_Recursion as a WHERE Tree.PId = a.ID 6 ) 7 SELECT * FROM Tree order by ID ASC;
执行一下,我们发现结果是所有与之相关的记录:
,目的达到,完结撒花...