本文来自: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. 对c#剪切板Clipboard占用的问题一点解决方法

    以前在百度写的文档,转移到此处 前几天做一个程序,其中有一个剪切板的操作,具体代码: Clipboard.SetText(“ABC”); 来完成一个复制字符串的操作. 自己调试通过,完全正常,然后就交 ...

  2. Prototypes analyze(二叉排序树,不同树形个数)

    Prototypes analyze 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 ALpha Ceiling Manufacturers (ACM) is ana ...

  3. FZU 2102 Solve equation(水,进制转化)&& FZU 2111(贪心,交换使数字最小)

    C Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Pra ...

  4. java获取指定长度随机数(版本1)

    获取指定长度随机数,含大小写字母和数字 package org.sw; import java.util.Random; /** * 得到指定位数的随机数 * @author mengzw * @si ...

  5. 某APK中使用了动态注册BroadcastReceiver,Launcher中动态加载此APK出现java.lang.SecurityException异常的解决方法

    在某APK中,通过如下方法动态注册了一个BroadcastReceiver,代码参考如下: @Override protected void onAttachedToWindow() { super. ...

  6. App签名--- Android

    步骤: 下面就Next即可

  7. asp.net 页面上传文件控件后台代码Request.Files获取不到

    今天开发中遇到页面文件上传控件选择了文件,而后台Request.Files.Count取值为0,之前开发中遇到过几次,老是忘掉,今天记下来. html: <input type="fi ...

  8. activiti笔记三 Activiti问题重现

    测试的时候出现一个异常: ContextLoader.initWebApplicationContext(308) | Context initialization failed org.spring ...

  9. __m128i的理解[转]

    __m128i被称为128bits的整数,当我们对其赋值时,调用 __m128i _mm_set1_epi32(int i) Sets the four signed 32-bit integer v ...

  10. linux----ulimit 限制

    ulimit -a 显示当前用户的各种限制. ulimit -n 的数值表示每个进程可以打开的文件数目. 一般情况下, ulimit -n 的数值是1024. 当进程打开的文件数目超过此限制时,该进程 ...