SQL Server2005使用CTE实现递归

日期: 2010-01-17 作者:wenjl520 来源:TechTarget中国 英文

  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

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

作者

wenjl520
wenjl520

相关推荐