T-SQL 公用表表达式(CTE)
公用表表达式(CTE)
在编写T-SQL代码时,往往需要临时存储某些结果集。前面我们已经广泛使用和介绍了两种临时存储结果集的方法:临时表和表变量。除此之外,还可以使用公用表表达式的方法。公用表表达式(Common Table Expression)是SQL Server2005版本的引入的一个特性。CTE可以看组是一个临时的结果集,可以再接下来来的一个SELECT,INSERT,UPDATE,DELETE,MERGE语句中多次引用。使用公用表达式CTE可以让语句更加清晰简练。与公用表达式作用类似的还有临时表和表变量。下面给出三种方法的对比。
1、3种方法比较
(一)、临时表:需要在临时数据库TempDB中通过I/O操作来创建表结构,一旦用户推出SQL Server环境则自动被删除。
(二)、表变量:在内存中以表结构的形式存在,其定义与变量一致,其使用与表类似,不需要产生I/O。
(三)、公用表表达式:Common Table Expression,定义在内存中保存的临时存储结果集对象,不产生I/O,不需要按照表变量这样定义,使用方法和表类似。可以自己引用,也可以再查询中被多次引用。
2、WITH AS的含义
WITH AS-做子查询部分(subquery factoring)。
它用于定义一个SQL片段,该片段会被是整个SQL语句所用到。如果WITH AS所以定的表名被调用两次以上,则优化器会自动将WITH AS所获取的数据放入临时表里,如果只是被调用一次,则不会。可以通过materialize将WITH AS短语里的数据强制放入全局临时表里。
WITH AS可以被紧跟着的一条SQL语句所使用多次,但不能被紧跟着的多条SQL语句使用。
WITH B AS
(
SELECT * FROM xxx WHERE Id > 5
)
SELECT * FROM B
3、CTE的定义
CTE的定义语法如下,主要包括3个部分。
(一)、Expression_name:CTE表达式的名称。
(二)、Column_name:列名列表。
(三)、CTE_query_definition:定义CTE结果集的Select查询语句
WITH expression_name [(column_name [,...n] )]
AS
(
cte_query_definition
)
根据微软对CTE好处的描述,可以归结为四点:
- 可以定义递归公用表表达式(CTE)
- 当不需要将结果集作为视图被多个地方引用时,CTE可以使其更加简洁
- GROUP BY语句可以直接作用于子查询所得的标量列
- 可以在一个语句中多次引用公用表表达式(CTE)
按照是否递归,可以将公用表(CTE)表达式分为递归公用表表达式和非递归公用表表达式.
非递归公用表表达式(CTE):
非递归公用表表达式(CTE)是查询结果仅仅一次性返回一个结果集用于外部查询调用。并不在其定义的语句中调用其自身的CTE。
非递归公用表表达式(CTE)的使用方式和视图以及子查询一致。
比如一个简单的非递归公用表表达式:
WITH CTE_Test
AS
(
SELECT * FROM Person_1
)
SELECT * FROM CTE_Test
公用表表达式的好处之一是可以在接下来一条语句中多次引用:

WITH CTE_Test
AS
(
SELECT * FROM Person_1
)
SELECT * FROM CTE_Test AS a --第一次引用
INNER JOIN CTE_Test AS b --第二次引用
ON a.Id = b.Id
ORDER BY a.Id DESC

虽然以上引用了多次,但是只是一条语句,所以可以正常执行。
如果多条语句引用,如下面这样,是会报错的。

WITH CTE_Test
AS
(
SELECT * FROM Person_1
)
SELECT * FROM CTE_Test SELECT * FROM CTE_Test

输出结果如下:
由于CTE只能在接下来一条语句中使用,因此,当需要接下来的一条语句中引用多个CTE时,可以定义多个,中间用逗号分隔,下面是一次定义多个CTE的例子:

WITH CTE_Test1
AS
(
SELECT * FROM Person_1
),
CTE_Test2
AS
(
SELECT * FROM Person_2
)
SELECT * FROM CTE_Test1
UNION
SELECT * FROM CTE_Test2

结果如下:
递归公用表表达式(CTE):
对于递归公用表达式来说,只需要在语句中定义两部分:
- 基本语句
- 递归语句
先建一张表栏目表如下,栏目Id,栏目名称,栏目的父栏目。
现在使用CTE查询其每个栏目是第几层栏目的代码如下:

WITH COL_CTE(Id,Name,ParentId,tLevel )
AS
(
--基本语句
SELECT Id,Name,ParentId,0 AS tLevel FROM Col
WHERE ParentId = 0
UNION ALL
--递归语句
SELECT c.Id,c.Name,c.ParentId,ce.tLevel+1 AS tLevel FROM COL as c
INNER JOIN COL_CTE AS ce --递归调用
ON c.ParentId = ce.Id
) SELECT * FROM COL_CTE

输出结果如下:
0表示顶级栏目。1就是1级栏目。语法非常优雅。就一个SELECT * FRON COL_CTE。这正是CTE强大的地方,但是,这要有约束,否则如果无限制递归可以会消耗掉非常多的系统资源。下面来看看如何限制递归的最大次数。
如将上面的查询语法改为:

WITH COL_CTE(Id,Name,ParentId,tLevel )
AS
(
--基本语句
SELECT Id,Name,ParentId,0 AS tLevel FROM Col
WHERE ParentId = 0
UNION ALL
--递归语句
SELECT c.Id,c.Name,c.ParentId,ce.tLevel+1 AS tLevel FROM COL as c
INNER JOIN COL_CTE AS ce
ON c.ParentId = ce.Id
) SELECT * FROM COL_CTE
OPTION(MAXRECURSION 2) --指定最大递归次数为2

我们知道在上面的查询中,要查到天河区新闻最少要递归3次,但是现在只递归2次,运行是什么结果呢?
提示信息如下:
消息 530,级别 16,状态 1,第 1 行
语句被终止。完成执行语句前已用完最大递归 2。
CTE是一种十分优雅的存在。CTE所带来最大的好处是代码可读性的提升,这是良好代码的必须品质之一。使用递归CTE可以更加轻松愉快的用优雅简洁的方式实现复杂的查询。
T-SQL 公用表表达式(CTE)的更多相关文章
- SQL Server进阶(六)表表达式--派生表、公用表表达式(CTE)、视图和内联表值函数
概述 表表达式是一种命名的查询表达式,代表一个有效地关系表.可以像其他表一样,在数据处理中使用表表达式. SQL Server支持四种类型的表表达式:派生表,公用表表达式,视图和内联表值函数. 为什么 ...
- SQL Server 公用表表达式(CTE)实现递归
公用表表达式简介: 公用表表达式 (CTE) 可以认为是在单个 SELECT.INSERT.UPDATE.DELETE 或 CREATE VIEW 语句的执行范围内定义的临时结果集.CTE 与派生表类 ...
- SQL Server 公用表表达式(CTE)实现递归的方法
公用表表达式简介: 公用表表达式 (CTE) 可以认为是在单个 SELECT.INSERT.UPDATE.DELETE 或 CREATE VIEW 语句的执行范围内定义的临时结果集.CTE 与派生表类 ...
- SQL 公用表表达式(CTE)
1.概念 公用表表达式(Common Table Expression)是SQL SERVER 2005版本之后引入的一个特性.CTE可以看作是一个临时的结果集,可以在接下来的一个SELECT,INS ...
- SQL Server温故系列(3):SQL 子查询 & 公用表表达式 CTE
1.子查询 Subqueries 1.1.单行子查询 1.2.多行子查询 1.3.相关子查询 1.4.嵌套子查询 1.5.子查询小结及性能问题 2.公用表表达式 CTE 2.1.普通公用表表达式 2. ...
- SQL Server 表表达式--派生表、公用表表达式(CTE)、视图和内联表值函数
概述 表表达式是一种命名的查询表达式,代表一个有效地关系表.可以像其他表一样,在数据处理中使用表表达式. SQL Server支持四种类型的表表达式:派生表,公用表表达式,视图和内联表值函数. 为什么 ...
- SQL Server中公用表表达式 CTE 递归的生成帮助数据,以及递归的典型应用
本文出处:http://www.cnblogs.com/wy123/p/5960825.html 我们在做开发的时候,有时候会需要一些帮助数据,必须需要连续的数字,连续间隔的时间点,连续的季度日期等等 ...
- sql server使用公用表表达式CTE通过递归方式编写通用函数自动生成连续数字和日期
问题:在数据库脚本开发中,有时需要生成一堆连续数字或者日期,例如yearly report就需要连续数字做年份,例如daily report就需要生成一定时间范围内的每一天日期.而自带的系统表mast ...
- 详解公用表表达式(CTE)
简介 对于SELECT查询语句来说,通常情况下,为了使T-SQL代码更加简洁和可读,在一个查询中引用另外的结果集都是通过视图而不是子查询来进行分解的.但是,视图是作为系统对象存在数据库中,那对于结果集 ...
随机推荐
- QT中QProcess调用命令行的痛苦经历
在QT程序中需要将某些目录和文件压缩为一个rar的压缩包,于是想到了在QT中通过QProcess类调用命令行的rar.exe来达到效果,但是没想到QProcess类用起来很麻烦,而且达不到效果,折腾了 ...
- angular-ui-bootstrap的进度条问题及解决
在测试angular-ui-bootstrap中的进度条的时候,用的是官方的示例代码,但是跑不起来. 经过代码比对之后,发现官方用的是0.14.3, 而我本地用的是0.13.3 (2015-08-09 ...
- python 守护进程 daemon
python 守护进程 daemon # -*-coding:utf-8-*- import sys, os '''将当前进程fork为一个守护进程 注意:如果你的守护进程是由inetd启动的,不要这 ...
- [MFC] 如何更改MFC程序图标
方法一: >_<:找一张ICO图标,替换programname/res/programname.ico文件,就可以啦,这时候你运行后得到的图标可能还是原来MFC的默认图标,这时候你只要把工 ...
- 深究JS异步编程模型
前言 上周5在公司作了关于JS异步编程模型的技术分享,可能是内容太干的缘故吧,最后从大家的表情看出"这条粉肠到底在说啥?"的结果:(下面是PPT的讲义,具体的PPT和示例代码在h ...
- 修改JSONArray里所有key的值
下面举一个代码的列子目的是实现如下功能: [{"userId":1,"userName":"plf"},{"userId" ...
- 从零开始学Bootstrap(2)
继从零开始学Bootstrap(1)后,我们需要实际做一些页面,边学边做.因为前端是一项非常注意实践的技术,知识点太多.太琐碎了,所以我们只能边学边做.根据我们想要做的效果,去查相应的资料.不要想着把 ...
- bzoj 3517: 翻硬币
3517: 翻硬币 Time Limit: 1 Sec Memory Limit: 128 MB Description 有一个n行n列的棋盘,每个格子上都有一个硬币,且n为偶数.每个硬币要么是正面 ...
- 高端PCB设计相关知识整理
PCB的设计布局布线实际上是一门很复杂而且大部分靠经验来做的学问,很多东西也有点玄乎,但有很多经验性的结论和公式还是可以参考的 保证原创,一天不一定写的完 CH.1 更加严重的电磁干扰 首先基本上微电 ...
- QQ邮箱的安全问题
下午同事群里有人提醒,小心欺诈邮件.邮件内容为你的帐户在XX存在异地登录,已经进入了[保护模式],如需解除请点击[解除保护模式] 除了链接之外,其它跟官方的是一模一样,包括标题. 那个链接的地址是:h ...