子查询有时使用起来很麻烦,因为所有的过滤和匹配逻辑都必须集成到子查询表达式中。如果只需要执行一个任务,且只需要使用一次杳询表达式,子查询是很好的选择。但子查询不能被重用,也不能很好地支持多个需求。这个问题的一个常见解决方法是用子查询的内容填充一个临时表,连接和过滤表达式可以应用于这个临时表,但性能很差,且会消耗大量的系统资源,使用临时表还需要创建和使用另一个表的权限。

CTE是这两个问题的最佳解决方法:它是一个只存在于内存的子查询,所以不需要特殊的权限,也不需要物理空间操作。CTE与传统的子查询不同,它是一个已命名的对象,可以像表那样重用和引用,并且灵活性高得多。CTE需在查询脚本中被使用之前进行定义,其定义形式是:用WITH开头,后跟一列放在括号中的输出列,之后是关键字AS和一个放在括号中的完整SELECT语句。

  1. WITH <expression_name> [ ( column_name [ , ... n ] ) ]
  2. AS
  3. ( CTE_query_definition )
  4. [ , < another_expresstion > ]
  5. <query>

首先为CTE提供一个名称,该名称类似于派生表的别名。然后可以提供CTE将返回的列表名称;如果CTE指定了它的所有返回列,则这是可选操作。最后,在圆括号中添加CTE查询的定义,然后添加使用CTE的主查询。


以下内容来自: 逆心(博客园)

WITH AS的含义

WITH AS-做子查询部分(subquery factoring)。

它用于定义一个SQL片段,该片段会被是整个SQL语句所用到。如果WITH AS所以定的表名被调用两次以上,则优化器会自动将WITH AS所获取的数据放入临时表里,如果只是被调用一次,则不会。可以通过materialize将WITH AS短语里的数据强制放入全局临时表里。

WITH AS可以被紧跟着的一条SQL语句所使用多次,但不能被紧跟着的多条SQL语句使用。

CTE的定义

根据微软对CTE好处的描述,可以归结为四点:

  • 可以定义递归公用表表达式(CTE)
  • 当不需要将结果集作为视图被多个地方引用时,CTE可以使其更加简洁
  • GROUP BY语句可以直接作用于子查询所得的标量列
  • 可以在一个语句中多次引用公用表表达式(CTE)

按照是否递归,可以将公用表(CTE)表达式分为递归公用表表达式和非递归公用表表达式.

非递归公用表表达式(CTE):

非递归公用表表达式(CTE)是查询结果仅仅一次性返回一个结果集用于外部查询调用。并不在其定义的语句中调用其自身的CTE。

非递归公用表表达式(CTE)的使用方式和视图以及子查询一致。

比如一个简单的非递归公用表表达式:

  1. WITH CTE_Test
  2. AS
  3. (
  4. SELECT * FROM Person_1
  5. )
  6. SELECT * FROM CTE_Test

公用表表达式的好处之一是可以在接下来一条语句中多次引用:

  1. WITH CTE_Test
  2.   AS
  3.   (
  4.   SELECT * FROM Person_1
  5.   )
  6.   SELECT * FROM CTE_Test AS a  --第一次引用
  7.   INNER JOIN CTE_Test AS b    --第二次引用
  8.   ON a.Id = b.Id
  9.   ORDER BY a.Id DESC

虽然以上引用了多次,但是只是一条语句,所以可以正常执行。

如果多条语句引用,如下面这样,是会报错的。

  1. WITH CTE_Test
  2.   AS
  3.   (
  4.   SELECT * FROM Person_1
  5.   )
  6.   SELECT * FROM CTE_Test
  7.  
  8.   SELECT * FROM CTE_Test

输出结果如下:

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

  1. WITH CTE_Test1
  2. AS
  3. (
  4. SELECT * FROM Person_1
  5. ),
  6. CTE_Test2
  7. AS
  8. (
  9. SELECT * FROM Person_2
  10. )
  11. SELECT * FROM CTE_Test1
  12. UNION
  13. SELECT * FROM CTE_Test2

结果如下:

递归公用表表达式(CTE):

    对于递归公用表达式来说,只需要在语句中定义两部分:

  •    基本语句
  •    递归语句

   先建一张表栏目表如下,栏目Id,栏目名称,栏目的父栏目。

现在使用CTE查询其每个栏目是第几层栏目的代码如下:

  1. WITH COL_CTE(Id,Name,ParentId,tLevel )
  2. AS
  3. (
  4. --基本语句
  5. SELECT Id,Name,ParentId,0 AS tLevel FROM Col
  6. WHERE ParentId = 0
  7. UNION ALL
  8. --递归语句
  9. SELECT c.Id,c.Name,c.ParentId,ce.tLevel+1 AS tLevel FROM COL as c
  10. INNER JOIN COL_CTE AS ce   --递归调用
  11. ON c.ParentId = ce.Id
  12. )
  13.  
  14. SELECT * FROM COL_CTE

输出结果如下:

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

如将上面的查询语法改为:

  1. WITH COL_CTE(Id,Name,ParentId,tLevel )
  2. AS
  3. (
  4. --基本语句
  5. SELECT Id,Name,ParentId,0 AS tLevel FROM Col
  6. WHERE ParentId = 0
  7. UNION ALL
  8. --递归语句
  9. SELECT c.Id,c.Name,c.ParentId,ce.tLevel+1 AS tLevel FROM COL as c
  10. INNER JOIN COL_CTE AS ce
  11. ON c.ParentId = ce.Id
  12. )
  13.  
  14. SELECT * FROM COL_CTE

  15. OPTION(MAXRECURSION 2)  --指定最大递归次数为2

我们知道在上面的查询中,要查到天河区新闻最少要递归3次,但是现在只递归2次,运行是什么结果呢?

提示信息如下:

  1. 消息 530,级别 16,状态 1,第 1
  2. 语句被终止。完成执行语句前已用完最大递归 2

Common Table Expressions (CTE)的更多相关文章

  1. Using Recursive Common table expressions to represent Tree structures

    http://www.postgresonline.com/journal/archives/131-Using-Recursive-Common-table-expressions-to-repre ...

  2. PostgreSQL: WITH Queries (Common Table Expressions)

    WITH 允许在 SELECT 语句中定义"表"的表达式,这个"表"的表达式称之为"公共表表达式(Common Table Expression)&q ...

  3. The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

    https://stackoverflow.com/questions/30045871/sorting-the-view-based-on-frequency-in-sql-server Just ...

  4. CTE(Common Table Expression) 公用表表达式

    在编写T-SQL代码时,往往需要临时存储某些结果集.前面我们已经广泛使用和介绍了两种临时存储结果集的方法:临时表和表变量.除此之外,还可以 使用公用表表达式的方法.公用表表达式(Common Tabl ...

  5. with as (cte common table expression) 公共表表达式

    SQL中 with as 的用法——使用公用表表达式(CTE)  公用表表达式 (CTE) 可以认为是在单个 SELECT.INSERT.UPDATE.DELETE 或 CREATE VIEW 语句的 ...

  6. SQLServer中的CTE(Common Table Expression)通用表表达式使用详解

    概述 我们经常会编写由基本的 SELECT/FROM/WHERE 类型的语句派生而来的复杂 SQL 语句.其中一种方案是需要编写在 FROM 子句内使用派生表(也称为内联视图)的 Transact-S ...

  7. 通用表表达式(Common Table Expression)

    问题:编写由基本的 SELECT/FROM/WHERE 类型的语句派生而来的复杂 SQL 语句. 方案1:编写在From子句内使用派生表(内联视图)的T-SQL查询语句. 方案2:使用视图 方案3:使 ...

  8. [SoapUI] Common XPath expressions

    选取节点 表达式 描述 nodename 选取此节点的所有子节点. / 从根节点选取. // 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置. . 选取当前节点. .. 选取当前节点的父节点 ...

  9. T-SQL中CTE表 with关键字

    Select字句在逻辑上是SQL语句最后进行处理的最后一步,所以,以下查询会发生错误: SELECT YEAR(OrderDate) AS OrderYear, COUNT(DISTINCT Cust ...

随机推荐

  1. silverlight visifire控件图表制作——silverlight 静态页面xaml

    一.silverlight 静态页面 1. 时间控件:DatePicker ,添加引用: xmlns:sdk="clr-namespace:System.Windows.Controls;a ...

  2. 使用ES6进行开发的思考

    ECMAScript6已经于近日进入了RC阶段,而早在其处于社区讨论时,我就开始一直在尝试使用ES6进行开发的方案.在Babel推出后,基于ES6的开发也有了具体可执行的解决方案,无论是Build还是 ...

  3. ViewDragHelper的使用

    一.ViewDragHelper的原理 是一个能够自用移动ViewGroup内部View的控件. 通过获取ViewGroup的点击事件,之后通过Scroller滑动来进行对ViewGroup内部控件的 ...

  4. eclipse添加xsd

    图片参考 http://wenku.baidu.com/link?url=DFHWF_yD-M-GCt2tfjs1npPs1xhNlyxik7i_pCBjw3oVlbssYrMvLNucuUpKg75 ...

  5. python代码风格规范

    类注释模板: :: class AnotherClass: """ 类注释 """ def method(self, arg1, arg2, ...

  6. AngularJS 父子控制器

    <!doctype html> <html ng-app="myApp"> <head> <script src="C:\\Us ...

  7. 为什么1Byte=8bit

    Byte是字节的意思,而字节在早期计算机内部是用标准ASCII码来表示的根据当时情况确定至多有128种需要表示的字符(当时是IBM的标准,现在普遍是255),也就是2的7次方用二进制的0和1来表示就需 ...

  8. Linux下使用VirtualBox安装Windows系统

    (文档比较长,只是写的详细,实际操作起来相对简单.) 由于一些特殊原因,我们并不能完全抛下Windows而使用Linux.VirtualBox 是一款虚拟机软件,支持多系统.在Linux下安装 Vir ...

  9. android 导航布局

    http://blog.csdn.net/wangjinyu501/article/details/8140588 http://www.cnblogs.com/hanyonglu/archive/2 ...

  10. JavaScrip常规函数

    JavaScrip常规函数包括以下8个:alert函数:显示一个警告对话框,包括一个"OK"按钮.confirm函数:显示一个确认对话框,包括一个"OK".&q ...