SQL 研究- Common Table Expression
2009-06-12 10:31:30 来源:WEB开发网Common Table Expression,简称 CTE,是SQL Server中的三种保存临时结果的方法之一。另外两种是临时表和View,当然你也可以说View并不保存数据,从这一点上来将, CTE更像View一些。
当你的查询需要从一个源表中统计出结果,基于这个结果再做进一步的统计,如此3次以上的话,你必然会用到View或者临时表,现在你也可以考虑用CTE了。
CTE的语法相当的简单, 如下:
With CTE的名字 AS
(
子查询
)
Select * from CTE的名字
CTE可以实现很多不可思议的功能,巧妙之处在于CTE可以出现自己的子查询里。让我们从简单的问题开始。
先假设一个需求,贵公司的员工表存放着员工号,员工直接经理的员工号,以及员工的Title,现在需要查询出各个员工所在的层次,从0开始。
于是你看到这样的表:
create table Employee
(
MgrId int,
EmpId int,
Title nvarchar(256)
)
表中的内容如下:
NULL 1 CEO
1 2 VP
2 3 Dev Manager
2 4 QA Manager
1 5 Sales Manager
3 30 Developer
3 31 Developer
4 40 Tester
4 41 Tester
你期望得到这样的结果:
NULL 1 CEO 0
1 2 VP 1
1 5 SalesManager 1
2 3 DevManager 2
2 4 QAManager 2
4 40 Tester 3
4 41 Tester 3
3 30 Developer 3
3 31 Developer 3
最后一列为所得到的层次数字。
使用如下的SQL能得到上面的效果:
With DirectReports as
(
select MgrId, EmpId, Title, 0 as [Level] from Employee where MgrId is null
union all
select a.MgrId, a.EmpId, a.Title, [Level]+1 as [Level]
from Employee a join DirectReports b on a.MgrId=b.EmpId
)
select * from DirectReports
为什么这个语句能够沿着CEO往下一层一层走下去,最终找到所有的员工呢?
显然要理解这一SQL必须理解包含在 as只有括号里的嵌套查询。它由两个查询结合而成:
select ..
Union All
Select..
这两个Select语句在CTE中有特殊的意义。
第一个Select子句被称为 锚点 语句,它返回的结果跟普通的SQL没有区别,在这里返回MgrID为null的员工。可见没有Manager是件多么美好的事情。
第二个子句就没那么普通了,它被称为 递归 语句,请注意到在from后面, Employee和DirectReport进行了链接操作。您一定会问,DirectReport的定义还没完成,这个名字代表什么结果呢?答案是它不只是代表了一个结果,实际上代表了一系列的结果。换句话说,在DirectReport这个名字下,包含着DirectReport0,DirectReport1,DirectReport2...这些较小的集合。
DirectReport0 是Employee和 锚点 结合的产物;
DirectReport1 是Employee和 DirectReport0 结合的产物;
依次类推, DirectReport n是Employee和DirectReport n-1结合的产物;
当DirectReport_n为空的时候,这个过程就结束了。
最后 锚点和DirectReport0,DirectReport1... 的并集就是DirectReport的内容。
作为一个程序员,每次看到递归的程序,必然会想到无限递归这个错误。为了避免了在开发阶段,无限递归导致数据库的崩溃,SQL Server提供了一个QueryHint, MaxRecursion,可以控制递归的最大层数,如果超过这个数字而仍为结束,则视为代码错误,强制退出。以本文所用的SQL为例,可以如下使用MaxRecursion。
With DirectReports as
(
select MgrId, EmpId, Title, 0 as [Level] from Employee where MgrId is null
union all
select a.MgrId, a.EmpId, a.Title, [Level]+1 as [Level]
from Employee a join DirectReports b on a.MgrId=b.EmpId
)
select * from DirectReports
Option(MaxRecursion 10)
正如我之前所说, CTE能完成更多的工作,让我们以后进一步挖掘。
- ››SQL Server 2008 R2 下如何清理数据库日志文件
- ››sqlite 存取中文的解决方法
- ››SQL2005、2008、2000 清空删除日志
- ››SQL Server 2005和SQL Server 2000数据的相互导入...
- ››sql server 2008 在安装了活动目录以后无法启动服...
- ››sqlserver 每30分自动生成一次
- ››sqlite 数据库 对 BOOL型 数据的插入处理正确用法...
- ››sql server自动生成批量执行SQL脚本的批处理
- ››sql server 2008亿万数据性能优化
- ››SQL Server 2008清空数据库日志方法
- ››sqlserver安装和简单的使用
- ››SQL Sever 2008 R2 数据库管理
更多精彩
赞助商链接