T-SQL 公用表表达式(CTE)

公用表表达式(CTE)

  在编写T-SQL代码时,每每须要临时存储某些结果集。前面咱们已经普遍使用和介绍了两种临时存储结果集的方法:临时表和表变量。除此以外,还能够使用公用表表达式的方法。公用表表达式(Common Table Expression)是SQL Server2005版本的引入的一个特性。CTE能够看组是一个临时的结果集,能够再接下来来的一个SELECT,INSERT,UPDATE,DELETE,MERGE语句中屡次引用。使用公用表达式CTE可让语句更加清晰简练。与公用表达式做用相似的还有临时表和表变量。下面给出三种方法的对比。数据库

  一、3种方法比较express

   (一)、临时表:须要在临时数据库TempDB中经过I/O操做来建立表结构,一旦用户推出SQL Server环境则自动被删除。优化

   (二)、表变量:在内存中以表结构的形式存在,其定义与变量一致,其使用与表相似,不须要产生I/O。spa

   (三)、公用表表达式:Common Table Expression,定义在内存中保存的临时存储结果集对象,不产生I/O,不须要按照表变量这样定义,使用方法和表相似。能够本身引用,也能够再查询中被屡次引用。3d

  二、WITH AS的含义code

  WITH AS-作子查询部分(subquery factoring)。对象

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

  WITH AS能够被紧跟着的一条SQL语句所使用屡次,但不能被紧跟着的多条SQL语句使用。递归

WITH B AS 
(
    SELECT * FROM xxx WHERE Id > 5
)
SELECT * FROM B

  三、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能够更加轻松愉快的用优雅简洁的方式实现复杂的查询。

相关文章
相关标签/搜索