对于Select查询语句来说,通常情况下,为了是T-SQL代码更加简洁和刻度,在一个查询中应用另外的结果集都是通过视图而不是查询进行分解的,但是,视图作为系统对象存储在数据库中,那对于结果集仅仅需要在存储过程或是用户自定义函数中使用一次的时候,使用视图就显得有限奢侈了。
公用表达式(Common Table Expression)是SQL Server2005版本之后引入的一个特性,.CTE可以看做是一个临时的结果集,可以再接下来的select,insert,update,delete,merge语句中被多次使用,使用公用表达式可以让语句更加清晰简练。
初次之外,根据微软对CTE好处的描述,可以归结为四点:
1、可以定义递归公用表达式(CTE)
2、当不需要将结果集作为视图被多个地方引用时,CTE可以使其更加简洁
3、group by 语句可以直接作用于子查询所得到的标量列
4、可以再一个语句中多次引用公用表达式(CET)
公用表达式(CTE)的定义
公用表达式的定义非常简单,只包含三个部分
1、公用表达式的名字(在with之后)
2、所涉及的列名(可选)
3、一个select语句(紧跟as之后)
在MSDN中的原型:
WITH expression_name [ ( column_name [,...n] ) ]
AS
( CTE_query_definition )
按照是否递归,可以将公用表(CTE)表达式分为递归公用表达式和非递归公用表达式。
非递归公用表达式(CTE)
非递归公用表达式(CTE)是查询结果仅仅一次性返回一个结果集用于外部查询调用。并不在其定义的语句中调用其自身的CTE
非递归公用表表达式CTE的使用方式和视图以及子查询一致
比如一个简单的非递归公用表达式:
with myExpress
as
(
select * from test
)
select * from myExpress
当然,公用表达式的好处一是可以再接下来的一条语句中多次引用:
前面我一直强调“在接下来的一条语句中”,意味着只能在接下来一条语句使用:
由于CTE只能在接下来一条语句中使用,因此,当需要接下来的一条语句中引用多个CTE时,可以定义多个,中间用逗号分隔:
递归公用表达式(CET)
递归公用表达式很像派生表(Derived Tables),值得是咋CTE内的语句中调用其自身的CTE,与派生表不同的是,CTE可以再一次定义多次进行派生递归,对于递归的概念,是指一个函数或是过程直接或者间接的调用其自身。
递归在C语言中实现的一个典型例子是斐波那契数列:
long fib(int n)
{
if(n==0) return 0;
if(n==1) return 1;
if(n>1) rerurn fib(n-1)+fib(n-2);
}
上面的C语言代码可以看到,要构成递归函数,需要两部分,第一部分是基础部分,返回固定值,也就是告诉程序合适开始递归。第二部分是循环部分,是函数或过程直接或者间接调用其自身进行递归。
对于递归公用表达式来说,实现原理也是相同的,同样需要在语句中定义两部分
1、基本语句
2、递归语句
在SQL这两部分通过union all连接结果集进行返回
比如:在AdventureWork中,我想知道每个员工所处的层级,0是最高级
这么复杂的查询通过递归CTE变得如此优雅和简洁,这也是CTE最强大的地方。
当然,越强大的力量,就需要被约束,如果使用不当的话,递归CTE可能会出现无限递归。从而大量消耗SQL Server的服务器资源,因此,SQL Server提供了Option选项,可以设定最大的递归次数:
还是上面的那个语句,限制了递归次数:
所提示的消息:
这个最大递归次数往往是根据数据所代表的具体业务相关的,比如这里,假设公司层级最多只有2层,没必要递归到多次。
CTE是一种十分优雅的存在,CTE所带来的最大的好处是代码的可读性的提升,这是良好代码的必须品质之一。使用递归CTE可以更加轻松愉快的用优雅简洁的方式实现复杂的查询。
转自http://www.cnblogs.com/CareySon/archive/2011/12/12/2284740.html