CTE(Common Table Expression) 公用表表达式
在编写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可以更加轻松愉快的用优雅简洁的方式实现复杂的查询。
CTE(Common Table Expression) 公用表表达式的更多相关文章
- SQLServer中的CTE(Common Table Expression)通用表表达式使用详解
概述 我们经常会编写由基本的 SELECT/FROM/WHERE 类型的语句派生而来的复杂 SQL 语句.其中一种方案是需要编写在 FROM 子句内使用派生表(也称为内联视图)的 Transact-S ...
- with as (cte common table expression) 公共表表达式
SQL中 with as 的用法——使用公用表表达式(CTE) 公用表表达式 (CTE) 可以认为是在单个 SELECT.INSERT.UPDATE.DELETE 或 CREATE VIEW 语句的 ...
- Sql — CTE公用表表达式和With用法总结
CTE(Common Table Expression) 公用表表达式,它是在单个语句的执行范围内定义的临时结果集,只在查询期间有效.它可以自引用,也可在同一查询中多次引用,实现了代码段的重复利用. ...
- 存储过程——公用表表达式(CTE)
目录 0. 背景说明 1. 定义及语法细节 1.1 基本定义 1.2 基本语法 1.3 多个CTE同时声明 1.4 CTE嵌套使用 2. CTE递归查询 2.1 简介 2.2 准备工作 2.3 计算每 ...
- 公用表表达式CTE
公用表表达式CTE表面上和派生表非常相似,看起来只是语义上的区别.但和派生表比较起来,CTE具有几个优势:第一,如果须要在一个CTE中引用另一个CTE,不需要像派生表那样嵌套,相反,只要简单地在同一个 ...
- T-SQL 公用表表达式(CTE)
公用表表达式(CTE) 在编写T-SQL代码时,往往需要临时存储某些结果集.前面我们已经广泛使用和介绍了两种临时存储结果集的方法:临时表和表变量.除此之外,还可以使用公用表表达式的方法.公用表表达式( ...
- 详解公用表表达式(CTE)
简介 对于SELECT查询语句来说,通常情况下,为了使T-SQL代码更加简洁和可读,在一个查询中引用另外的结果集都是通过视图而不是子查询来进行分解的.但是,视图是作为系统对象存在数据库中,那对于结果集 ...
- T-SQL查询进阶--详解公用表表达式(CTE)
简介 对于SELECT查询语句来说,通常情况下,为了使T-SQL代码更加简洁和可读,在一个查询中引用另外的结果集都是通过视图而不是子查询来进行分解的. 但是,视图是作为系统对象存在数据库中,那对于结果 ...
- 公用表表达式(CTE)
在编写T-SQL代码时,往往需要临时存储某些结果集.前面我们已经广泛使用和介绍了两种临时存储结果集的方法:临时表和表变量.除此之外,还可以使用公用表表达式的方法.公用表表达式(Common Table ...
随机推荐
- P1005 矩阵取数游戏(动态规划+高精度)
题目链接:传送门 题目大意: 给定长度为m的数列aj,每次从两端取一个数,得到2k * aj的价值(k为当前的次数,从1开始到m),总共有n行这样的数列,求最大价值总和. 1 ≤ n, m ≤ 80, ...
- PDO数据库引擎
PDO概述1.PDO是一种数据库访问抽象层,你不必使用以前的 mysqli_xx 之类只能访问 mysql数据库.使用PDO可以连接mysql.msssql.oracle等等,而不必重写代码.2.PD ...
- java利用Comparator接口对自定义数组排序
import java.util.Arrays; import java.util.Comparator; public class MySort { public static void main( ...
- RESTful规范(二)
七 解析器 解析器的作用: -用来解析前台传过来的数据编码方式 urlencoded:form表单:name=lqz&age= formdata :上传文件:--dadfgdgag-- jso ...
- 识别假tf卡工具
h2testwhttps://www.heise.de/download/product/h2testw-50539使用HaraldBögeholz的免费测试工具H2testw,可以检查存储介质(如硬 ...
- C++学习(三十三)(C语言部分)之 队列
队列测试代码笔记如下: #include<stdio.h> #define SIZE 10 typedef struct Queue { int data[SIZE]; //队列的容量 i ...
- 【分布式事务】阿里fescar
一.什么是Fescar FESCAR(Fast & Easy Commit And Rollback) 是一个用于微服务架构的分布式事务解决方案,它的特点是高性能且易于使用,旨在实现简单并快速 ...
- PyMongo 常见问题
PyMongo是线程安全的吗PyMongo是线程安全的,并且为多线程应用提供了内置的连接池 PyMongo是进程安全的吗PyMongo不是进程安全的,如果你在fork()中使用MongoClient实 ...
- openresty 编译ngx_pagespeed 模块-docker 构建
ngx_pagespeed 是一个很不错的web 优化模块,我们通过简单的配置就可以对于web页面的加载有很大的提升 ngx_pagespeed 依赖psol 模块 Dockerfile # Do ...
- mysql-8.0.12 安装+配置, Navicat Premium 12 安装+激活
1.解压到安装目录,如:D:\mysql-8.0.12-winx64 2.将以下配置文件粘贴到安装目录,并保存为my.ini,注意:使用ansi 而非utf-8编码格式保存 [mysql] # 设置m ...