本文来自:http://www.cnblogs.com/wenjl520/archive/2010/01/18/1650393.html

CTE递归原理:

递归CTE是由两个最小查询构建的.第一个是定位成员(Anchor Member,AM),它是一个非递归查询,第二个是递归成员(Recursive Member,RM),它是递归查询.在CTE括号中(AS 子句之后),定义独立查询或引用回相同CTE的查询,AM与RM由UNION ALL语句分隔.AM紧被调用一次,RM将被重复调用,直到查询不在返回数据行为止.可以使用UNION或UNION ALL运算符彼此追加多个AM,具体取决于是否希望删除重复数据(必须使用UNION ALL运算符来追加递归成员).语法如下:


--需要查询字段集合,也是查询结果的字段集合
WITH SimpleRecursive(filed names)
AS
(
    --查询定位成员表
    <SELECT Statement for the Anchor Member>
    UNION ALL
    --查询递归成员表
    <SELECT Statement for the Recursive Member>
)
SELECT * FROM SimpleRecursive

实例:我们将创建一个员工表和一个名为ReportsTo的自引用字段,其引用回Emloyee_ID,然后编写一个查询,其返回像Stephen(Employee_ID=2)报告的所有员工以及向Stephen的下属报告的所有员工.

代码清单:


--创建表
CREATE TABLE Employee_Tree
    (
      Employee_NM NVARCHAR(50) ,
      Employee_ID INT PRIMARY KEY ,
      ReportsTo INT
    ) INSERT  INTO Employee_Tree
VALUES  ( 'Richard', 1, NULL )
INSERT  INTO Employee_Tree
VALUES  ( 'Stephen', 2, 1 )
INSERT  INTO Employee_Tree
VALUES  ( 'Clemens', 3, 2 )
INSERT  INTO Employee_Tree
VALUES  ( 'Malek', 4, 2 )
INSERT  INTO Employee_Tree
VALUES  ( 'Goksin', 5, 4 )
INSERT  INTO Employee_Tree
VALUES  ( 'Kimberly', 6, 1 )
INSERT  INTO Employee_Tree
VALUES  ( 'Ramesh', 7, 5 )
--创建递归查询
WITH    SimpleRecursive ( Employee_NM, Employee_ID, ReportsTo )
          AS ( SELECT   Employee_NM ,
                        Employee_ID ,
                        ReportsTo
               FROM     Employee_Tree
               WHERE    Employee_ID = 2
               UNION ALL
               SELECT   p.Employee_NM ,
                        p.Employee_ID ,
                        p.ReportsTo
               FROM     Employee_Tree p
                        INNER JOIN SimpleRecursive A ON A.Employee_ID = p.ReportsTo
             )
    SELECT  sr.Employee_ID AS empid ,
            sr.Employee_NM AS Emp ,
            et.Employee_NM AS Boss
    FROM    SimpleRecursive sr
            INNER JOIN Employee_Tree et ON sr.ReportsTo = et.Employee_ID

查询结果:

递归过程开始于Employee_ID=2的位置(定义成员或第一个SELECT).它获取该记录,并使用递归递归成员(UNION ALL之后的SELECT)获取所有向Stephen报告的记录以及该记录的子记录.(Goksin向Malek报告,Malek向Stephen报告).每一个后续递归都尝试找到更多的子记录.它们以先前递归已经找到的员工作为父记录.最终该递归不返回结果,这是导致递归停止的原因(为什么没有返回Kimberly的原因).如果该定位成员被改变成Employee_ID=1,则Kimberly也将在结果中被返回.

根据设计,递归成员将一直查找子记录,并可以无限循环.如果您怀疑将会进行许多循环,并希望限制递归调用次数,可以使用OPTION子句在外部查询的后面指定MAXRECURSION选项.

OPTION(MAXRECURSION 25)

这一选项将使sql server2005在cte出现指定限制时产生一条错误.默认情况下,限制为100(即省略该选项时).要不想指定选项.必须将MAXRECURSION设为0.

代码清单:


WITH    SimpleRecursive ( Employee_NM, Employee_ID, ReportsTo )
          AS ( SELECT   Employee_NM ,
                        Employee_ID ,
                        ReportsTo
               FROM     Employee_Tree
               WHERE    Employee_ID = 2
               UNION ALL
               SELECT   p.Employee_NM ,
                        p.Employee_ID ,
                        p.ReportsTo
               FROM     Employee_Tree p
                        INNER JOIN SimpleRecursive A ON A.Employee_ID = p.ReportsTo
             )
    SELECT  sr.Employee_ID AS empid ,
            sr.Employee_NM AS Emp ,
            et.Employee_NM AS Boss
    FROM    SimpleRecursive sr
            INNER JOIN Employee_Tree et ON sr.ReportsTo = et.Employee_ID
            OPTION(MAXRECURSION 2)

结果如下:

还会看到以下错误:

消息 530,级别 16,状态 1,第 1 行
语句被终止。完成执行语句前已用完最大递归 2。
    一种可以避免出现此异常的方法是使用一个所产生的列来跟踪所在的级别,并包含在WHERE子句中,而不是MAXRECURSION.以下结果与上一示例相同,但不产生错误.

代码清单:


WITH    SimpleRecursive ( Employee_NM, Employee_ID, ReportsTo ,Sublevel)
          AS ( SELECT   Employee_NM ,
                        Employee_ID ,
                        ReportsTo,
                        0
               FROM     Employee_Tree
               WHERE    Employee_ID = 2
               UNION ALL
               SELECT   p.Employee_NM ,
                        p.Employee_ID ,
                        p.ReportsTo,
                        Sublevel + 1
               FROM     Employee_Tree p
                        INNER JOIN SimpleRecursive A ON A.Employee_ID = p.ReportsTo
             )
    SELECT  sr.Employee_ID AS empid ,
            sr.Employee_NM AS Emp ,
            et.Employee_NM AS Boss      
    FROM    SimpleRecursive sr
            INNER JOIN Employee_Tree et ON sr.ReportsTo = et.Employee_ID
            WHERE    Sublevel <=2

ok,CTE递归查询完成了.

版权说明

如果标题未标有<转载、转>等字则属于作者原创,欢迎转载,其版权归作者和博客园共有。 
  作      者:温景良
  文章出处:http://wenjl520.cnblogs.com/  或  http://www.cnblogs.com/

SQL Server2005使用CTE实现递归的更多相关文章

  1. SQL Server 公用表表达式(CTE)实现递归

    公用表表达式简介: 公用表表达式 (CTE) 可以认为是在单个 SELECT.INSERT.UPDATE.DELETE 或 CREATE VIEW 语句的执行范围内定义的临时结果集.CTE 与派生表类 ...

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

    公用表表达式简介: 公用表表达式 (CTE) 可以认为是在单个 SELECT.INSERT.UPDATE.DELETE 或 CREATE VIEW 语句的执行范围内定义的临时结果集.CTE 与派生表类 ...

  3. SQL点点滴滴_公用表表达式(CTE)递归的生成帮助数据

    本文的作者辛苦了,版权问题特声明本文出处:http://www.cnblogs.com/wy123/p/5960825.html 工作有时候会需要一些帮助数据,必须需要连续的数字,连续间隔的时间点,连 ...

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

    问题:在数据库脚本开发中,有时需要生成一堆连续数字或者日期,例如yearly report就需要连续数字做年份,例如daily report就需要生成一定时间范围内的每一天日期.而自带的系统表mast ...

  5. SQL Server封闭掉 触发器递归

    SQL Server关闭掉 触发器递归SQL Server  是有一个开关, 可以关闭掉 触发器递归的.EXEC sp_dboption '数据库名字', 'recursive triggers', ...

  6. 在WinCC中通过VBS操作SQL Server2005

    在项目中需要在一定条件满足时,保存一些数据到数据库中,并可根据条件查询.考虑到WinCC6.2以后采用的就是SQL Server2005数据库,所以直接利用该数据库即可,通过SQL Server Ma ...

  7. java连接sql server2005

    转自:http://blog.sina.com.cn/s/blog_889b58310100zqyz.html 一:配置 第一步:在网上下载SQLServer2005的驱动包 http://www.m ...

  8. 公用表表达式(CTE)递归的生成帮助数据

    本文的作者辛苦了,版权问题特声明本文出处:http://www.cnblogs.com/wy123/p/5960825.html 工作有时候会需要一些帮助数据,必须需要连续的数字,连续间隔的时间点,连 ...

  9. SQL Server2005索引碎片分析和解决方法

    SQL Server2005索引碎片分析和解决方法 本文作者(郑贤娴),请您在阅读本文时尊重作者版权. 摘要: SQL Server,为了反应数据的更新,需要维护表上的索引,因而这些索引会形成碎片.根 ...

随机推荐

  1. 01-Java学习笔记

    本系列笔记由常彦博整理,请知悉 目  录 一. Java技术基础.................................................................... ...

  2. python学习之路-5 基础进阶篇

    本篇涉及内容 双层装饰器字符串格式化 双层装饰器 装饰器基础请点我 有时候一个功能需要有2次认证的时候就需要用到双层装饰器了,下面我们来通过一个案例详细介绍一下双层装饰器: 执行顺序:自上而下 解释顺 ...

  3. python - 文件

    ''' 模式 描述 r 以读方式打开文件,可读取文件信息. w 以写方式打开文件,可向文件写入信息.如文件存在,则清空该文件,再写入新内容 a 以追加模式打开文件(即一打开文件,文件指针自动移到文件末 ...

  4. 《TCP/IP具体解释卷2:实现》笔记--4种不同类型的mbuf

    mbuf的主要用途是保存子进程和网络接口间互相传递的用户数据.但mbuf也用于保存其它各种数据:源于目的地址.插口 选项等等. 以下介绍我们要遇到的四种类型的mbuf,它们根据在成员m_flag中填写 ...

  5. 学习Android之SharedPreferences使用

    效果图例如以下: 当我们想让自己的属性设置保存下来,这时就须要SharedPreferences. 上面这个小程序,音乐状态是保存下来的.使用的上一次退出的状态. 进入DDMS,data文件下的dat ...

  6. Lua内存泄漏应对方法[转]

    转自http://blog.csdn.net/xocoder/article/details/42685685 由于目前正在负责的项目是一个二次开发项目,而且留给我们的代码质量实在让人无力吐槽,所以遇 ...

  7. IOS上 关于状态栏的相关设置(UIStatusBar)

    知识普及 ios上状态栏 就是指的最上面的20像素高的部分 状态栏分前后两部分,要分清这两个概念,后面会用到: 前景部分:就是指的显示电池.时间等部分: 背景部分:就是显示黑色或者图片的背景部分: 如 ...

  8. JS实现下拉框选中不同的项,对应显示不同的信息

    实现的效果如下图: 页面代码 下拉框: <select id="select3" name="select3" onchange="showli ...

  9. 上拉、下拉UITableView,交互式 模态弹出(自定义弹出动画)

    部分代码 InteractiveTransition 类继承NSObject: - (instancetype)initWithPresentingController:(UITableViewCon ...

  10. 省市联动JQ封装比较简洁调用的方法

    前言 因为省市联动的需求在每个项目几乎存在,所以本人也对此在web页面通过封装比较简洁的JQ方法循环判断调用调用后台获取数据再绑定到Select表单上.如果对代码有什么疑问或者更好办法可以在评论区留言 ...