SQL Server 公用表表达式(CTE)实现递归的方法

公用表表达式简介:

公用表表达式 (CTE) 可以认为是在单个 SELECT、INSERT、UPDATE、DELETE 或 CREATE VIEW 语句的执行范围内定义的临时结果集。CTE 与派生表类似,具体表现在不存储为对象,并且只在查询期间有效。与派生表的不同之处在于,公用表表达式 (CTE) 具有一个重要的优点,那就是能够引用其自身,从而创建递归 CTE。递归 CTE 是一个重复执行初始 CTE 以返回数据子集直到获取完整结果集的公用表表达式。

下面先创建一个表,并插入一些数据:

create table Role_CTE
(
 Id  int    not null,
 Name nvarchar(32) not null,
 ParentId int  not null
)
insert into Role_CTE(Id,Name,ParentId)
select '1','超级管理员','0' union
select '2','管理员A','1' union
select '3','管理员B','2' union
select '4','会员AA','2' union
select '5','会员AB','2' union
select '6','会员BA','3' union
select '7','会员BB','3' union
select '8','用户AAA','4' union
select '9','用户BBA','7'
-- 创建一个复合聚集索引
create clustered index Clu_Role_CTE_Index
on Role_CTE(Id,ParentId)
with
(
 pad_index=on,
 fillfactor=50,
 drop_existing=off,
 statistics_norecompute=on
)
select * from Role_CTE

查找指定节点的所有子孙节点:

使用普通 sql 语句实现:

declare @level int
declare @node int
declare @ResTab table
(
 node int not null,
 lv  int not null
)
set @level=0  -- 表示初始的等级
set @node=3   --表示初始的节点ID,即从指定的哪个节点开始查找
insert into @ResTab    -- 为表变量插入初始的数据
select Id,@level
from Role_CTE
where Id=@node
while(@@ROWCOUNT>0)
begin
 set @level=@level+1
 insert into @ResTab
 select b.Id,@level
 from @ResTab a
 join Role_CTE b on a.node=b.ParentId and lv=@level-1 -- join 等于 inner join(内连接)和自连接
end
select a.node,b.Name,a.lv
from @ResTab a
left join Role_CTE b on a.node=b.Id

以上是根据指定节点ID(3),查找父节点ID(即字段 ParentId)等于指定的节点ID,如果有就插入,并继续循环。

PS:lv=@level-1 是重点,不然会进入死循环,作用就是限制只插入一次。

如果需要限制循环的次数,即递归的层数,那么只需要在 while 条件里面添加一个限制即可。如下:

declare @level int
declare @node int
declare @num int
declare @ResTab table
(
 node int not null,
 lv  int not null
)
set @level=0  -- 表示初始的等级
set @node=3   --表示初始的节点ID,即从指定的哪个节点开始查找
set @num=1  -- 指定递归层级,即循环的次数
insert into @ResTab    -- 为表变量插入初始的数据
select Id,@level
from Role_CTE
where Id=@node
while(@@ROWCOUNT>0 and @level<@num)
begin
 set @level=@level+1
 insert into @ResTab
 select b.Id,@level
 from @ResTab a
 join Role_CTE b on a.node=b.ParentId and lv=@level-1 -- join 等于 inner join(内连接)和自连接
end
select a.node,b.Name,a.lv
from @ResTab a
left join Role_CTE b on a.node=b.Id

当然,如果指定了循环次数,就可以不用 while 判断语句的 @@rowcount>0 了。

使用 SQL CTE 实现:

declare @node int
set @node=3;
with temp_cte
as
(
 select Id,Name,0 lv  -- 查询出“根节点”,即指定的起始节点
 from Role_CTE
 where Id=@node
 union all
 select b.Id,b.Name,a.lv+1
 from temp_cte a
 join Role_CTE b on a.Id=b.ParentId
)
select * from temp_cte

使用 CTE 控制递归的层数,与上面类似。如下:

declare @node int
declare @num int
set @node=3;
set @num=1;
with temp_cte
as
(
 select Id,Name,0 lv  -- 查询出“根节点”,即指定的起始节点
 from Role_CTE
 where Id=@node
 union all
 select b.Id,b.Name,a.lv+1
 from temp_cte a
 join Role_CTE b on a.Id=b.ParentId
     and a.lv<@num  --控制递归层数
)
select * from temp_cte

查找指定节点的所有祖先节点:

使用普通 sql 语句实现:

declare @level int
declare @node int
declare @num int
declare @ResTab table
(
 node int not null,
 lv  int not null
)
set @level=0 -- 表示初始的等级
set @node=8   --表示初始的节点ID,即从指定的哪个节点开始查找
set @num=2  -- 指定递归层级,即循环的次数
while(@level<=@num and @node is not null) -- 如果为空就表示没有查到父级了
begin
 insert into @ResTab
 select @node,@level
 set @level=@level+1
 select @node=ParentId
 from Role_CTE
 where Id=@node
end
select a.node,b.Name,a.lv
from @ResTab a
left join Role_CTE b on a.node=b.Id

使用 SQL CTE 实现:

declare @node int
declare @num int
set @node=8;
set @num=2;
with temp_cte
as
(
 select Id,Name,ParentId,0 lv  -- 查询出“根节点”,即指定的起始节点
 from Role_CTE
 where Id=@node
 union all
 select b.Id,b.Name,b.ParentId,a.lv+1
 from temp_cte a
 join Role_CTE b on a.ParentId=b.Id
     and a.lv < @num  --控制递归层数
)
select * from temp_cte

以上所述是小编给大家介绍的SQL Server 公用表表达式(CTE)实现递归的方法,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 使用SqlServer CTE递归查询处理树、图和层次结构

    CTE(Common Table Expressions)是从SQL Server 2005以后版本才有的.指定的临时命名结果集,这些结果集称为CTE. 与派生表类似,不存储为对象,并且只在查询期间有效.与派生表的不同之处在于,CTE 可自引用,还可在同一查询中引用多次.使用CTE能改善代码可读性,且不损害其性能. 递归CTE是SQL SERVER 2005中重要的增强之一.一般我们在处理树,图和层次结构的问题时需要用到递归查询. CTE的语法如下 WITH CTE AS ( SELECT Em

  • 使用SQLSERVER 2005/2008 递归CTE查询树型结构的方法

    下面是一个简单的Family Tree 示例: 复制代码 代码如下: DECLARE @TT TABLE (ID int,Relation varchar(25),Name varchar(25),ParentID int) INSERT @TT SELECT 1,' Great GrandFather' , 'Thomas Bishop', null UNION ALL SELECT 2,'Grand Mom', 'Elian Thomas Wilson' , 1 UNION ALL SELE

  • SQL Server 公用表表达式(CTE)实现递归的方法

    公用表表达式简介: 公用表表达式 (CTE) 可以认为是在单个 SELECT.INSERT.UPDATE.DELETE 或 CREATE VIEW 语句的执行范围内定义的临时结果集.CTE 与派生表类似,具体表现在不存储为对象,并且只在查询期间有效.与派生表的不同之处在于,公用表表达式 (CTE) 具有一个重要的优点,那就是能够引用其自身,从而创建递归 CTE.递归 CTE 是一个重复执行初始 CTE 以返回数据子集直到获取完整结果集的公用表表达式. 下面先创建一个表,并插入一些数据: crea

  • sql server使用公用表表达式CTE通过递归方式编写通用函数自动生成连续数字和日期

    问题: 在数据库脚本开发中,有时需要生成一堆连续数字或者日期,例如yearly report就需要连续数字做年份,例如daily report就需要生成一定时间范围内的每一天日期. 而自带的系统表master..spt_values存在一定的局限性,只是从0到2047(验证脚本:select * from master..spt_values b where b.type = 'P'),也不能直接生成连续日期. 可能大部分人会想到一个笨办法,通过while循环去逐条插入数据到临时表,每次数字加1

  • SQL Server使用T-SQL进阶之公用表表达式(CTE)

    在编写T-SQL代码时,往往需要临时存储某些结果集.前面我们已经广泛使用和介绍了两种临时存储结果集的方法:临时表和表变量.除此之外,还可以使用公用表表达式的方法. 公用表表达式(Common Table Expression)是SQL Server2005版本的引入的一个特性.CTE可以看组是一个临时的结果集,可以再接下来来的一个SELECT,INSERT,UPDATE,DELETE,MERGE语句中多次引用. 一.3种方法比较 使用公用表达式CTE可以让语句更加清晰简练.与公用表达式作用类似的

  • MariaDB表表达式之公用表表达式(CTE)

    目录 前言 1.非递归CTE 2.递归CTE 2.1 语法 2.2 递归CTE示例(1) 2.2 递归CTE示例(2) 2.2 递归CTE示例(3) 总结 前言 公用表表达式(Common Table Expression,CTE)和派生表类似,都是虚拟的表,但是相比于派生表,CTE具有一些优势和方便之处. CTE有两种类型:非递归的CTE和递归CTE. CTE是标准SQL的特性,属于表表达式的一种,MariaDB支持CTE,MySQL 8才开始支持CTE. 1.非递归CTE CTE是使用WIT

  • SQL2005 学习笔记 公用表表达式(CTE)

    公用表表达式 (CTE) 可以认为是在单个 SELECT.INSERT.UPDATE.DELETE 或 CREATE VIEW 语句的执行范围内定义的临时结果集. CTE 与派生表类似,具体表现在不存储为对象,并且只在查询期间有效. 与派生表的不同之处在于,CTE 可自引用,还可在同一查询中引用多次. CTE可用于: 1.创建递归查询(我个人认为CTE最好用的地方) 2.在同一语句中多次引用生成的表 CTE优点: 使用 CTE 可以获得提高可读性和轻松维护复杂查询的优点. 查询可以分为单独块.简

  • mysql8 公用表表达式CTE的使用方法实例分析

    本文实例讲述了mysql8 公用表表达式CTE的使用方法.分享给大家供大家参考,具体如下: 公用表表达式CTE就是命名的临时结果集,作用范围是当前语句. 说白点你可以理解成一个可以复用的子查询,当然跟子查询还是有点区别的,CTE可以引用其他CTE,但子查询不能引用其他子查询. 一.cte的语法格式: with_clause: WITH [RECURSIVE] cte_name [(col_name [, col_name] ...)] AS (subquery) [, cte_name [(co

  • sql server 2005中使用with实现递归的方法

    复制代码 代码如下: WITH fw_requestion_note_temp(old_apply_id) AS ( --取根节点放入临时表 SELECT old_apply_id FROM fw_requestion_note --WHERE old_apply_id = 'e741470e-8b5c-4f91-9b03-c7474d103aef' --根据已取到的数据递归取其字节点的数据 UNION ALL SELECT fw.old_apply_id FROM fw_requestion_

  • 关于SQL中CTE(公用表表达式)(Common Table Expression)的总结

    一.WITH AS的含义 WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNION ALL的不同部分,作为提供数据的部分. 特别对于UNION ALL比较有用.因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可.如果WITH AS短语所定义的表名

  • SqlServer使用公用表表达式(CTE)实现无限级树形构建

    SQL Server 2005开始,我们可以直接通过CTE来支持递归查询,CTE即公用表表达式 公用表表达式(CTE),是一个在查询中定义的临时命名结果集将在from子句中使用它.每个CTE仅被定义一次(但在其作用域内可以被引用任意次),并且在该查询生存期间将一直生存.可以使用CTE来执行递归操作. DECLARE @Level INT=3 ;WITH cte_parent(CategoryID,CategoryName,ParentCategoryID,Level) AS ( SELECT c

  • SQL Server 树形表非循环递归查询的实例详解

    很多人可能想要查询整个树形表关联的内容都会通过循环递归来查...事实上在微软在SQL2005或以上版本就能用别的语法进行查询,下面是示例. --通过子节点查询父节点 WITH TREE AS( SELECT * FROM Areas WHERE id = 6 -- 要查询的子 id UNION ALL SELECT Areas.* FROM Areas, TREE WHERE TREE.PId = Areas.Id ) SELECT Area FROM TREE --通过父节点查询子节点 WIT

随机推荐