本文来自: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. ubuntu 配置jdk

    shawn@e014-anle-lnx:~$ sudo su # chmod 777 jdk-6u27-linux-i586.bin # ./jdk-6u27-linux-i586.bin # mv ...

  2. Android UI布局之FrameLayout

    一个FrameLayout对象就好比一块屏幕上提前预定好的空白区域.然后能够填充一些元素到里边.例如说一张图片等.须要注意的是,全部的元素都被放置在FrameLayout区域最左边上的区域.并且无法为 ...

  3. 移动支付之智能IC卡与Android手机进行NFC通信

    本文来自http://blog.csdn.net/hellogv/ .引用必须注明出处.        眼下常见的智能IC卡执行着JavaCard虚拟机.智能IC卡上能够执行由精简后的Java语言编写 ...

  4. CreateFile使用方法和样例

    函数原型: HANDLE CreateFile( LPCTSTR lpFileName, //指向文件名称的指针 DWORD dwDesiredAccess, //訪问模式(写/读) DWORD dw ...

  5. C#基础学习心得(一)

    类的成员 数据成员:字段,常量(const) 函数成员:方法,属性,索引器,构造函数,析构函数,事件 类的声明 实例成员:对象相关性,不同于同一类的其他实例 静态成员:常量,static修饰的字段,方 ...

  6. 使用Battery Historian(android 5.0)

    http://hukai.me/android-performance-battery/可以先参考这篇文章 1$ adb shell dumpsys batterystats > xxx.txt ...

  7. codeforces 342D Xenia and Dominoes(状压dp+容斥)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud D. Xenia and Dominoes Xenia likes puzzles ...

  8. SQL语句 计算某段时间工作日的天数(除了周六日)

    --只是加了固定日期,可以根据需求给成变量形式(BY 少年工藤) -思路:根据日期区间循环判断每一天是周日(1).周六(7)不变,其他加1 1 DECLARE @DAY DATE,@COUNT INT ...

  9. Bootstrap 静态分页 和 jquery_pagination插件 动态分页

    第一种Bootstrap 实例 - 默认的分页 <!DOCTYPE html> <html> <head> <title>Bootstrap 实例 - ...

  10. HTML5 JavaScript 文件上传

    function fileUpload(targetUrl) { // 隐藏表单名称 var inputName = '_fileselect'; // 文件尺寸 this.fileSize = 0; ...