【译】高级T-SQL进阶系列 (三)【中篇】:理解公共表表达式(CTEs)
【译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正】
原文链接:传送门。
一个简单的CTE例子
如前所述,CTE‘s提供给你了一个方法来更容易的书写复杂的代码以提高其可读性。假设你有列表1所示的代码:
USE AdventureWorks2012;
GO
SELECT YearMonth, ProductID, SumLineTotal
FROM (
SELECT CONVERT(CHAR(7),ModifiedDate,120) AS YearMonth
, ProductID
, SUM(LineTotal) AS SumLineTotal
FROM Sales.SalesOrderDetail
GROUP BY ProductId, CONVERT(CHAR(7),ModifiedDate,120)
) MonthlyProductSales
WHERE YearMonth = '2008-06';
列表1:带有子查询的代码
列表1具有一个SELECT语句,其带有一个在FROM子句中的子查询。这个子查询是一个具有别名MonthlyProductSales 的派生表,其对ModifiedDate字段的每一个Year/Month组合都总结了其LineTotal 数量。从我的MonthlyProductSales 子查询的结果中,我对结果进行约束,使得其仅仅返回那些年和月为 2008,06的数据行。
虽然列表1的代码已经是相当的简洁了,我们可以通过用一个CTE来重写它以提高它的可读性,就像我在列表2中所做的那样。
USE AdventureWorks2012;
GO
-- CTE Definition
WITH MonthlyProductSales AS
(
SELECT CONVERT(CHAR(7),ModifiedDate,120) AS YearMonth
, ProductID
, SUM(LineTotal) AS SumLineTotal
FROM Sales.SalesOrderDetail
GROUP BY ProductId, CONVERT(CHAR(7),ModifiedDate,120)
)
-- SELECT statement referencing CTE
SELECT * FROM MonthlyProductSales
WHERE YearMonth = '2008-06';
列表2:使用CTE对列表1的代码进行重写
在列表2中我将列表1中的派生表子查询移到了一个名为MonthlyProductSales的CTE中。接下来我将SELECT语句中的子查询用CTE的名字来替换,在这个示例中,是MonthlyProductSales。通过移动列表1中的子查询到一个CTE的定义中,很多人都会发现列表2中的代码更容易阅读和维护。
使用多个CTE’s 的示例
我在列表1中的代码并不是那么复杂。如果你的代码比较复杂并且包含多个子查询,那么你应该考虑重写它,从而使它更易维护且更具有可读性。而重写的方法之一便是移除子查询并用CTE来对其进行重写。
为了演示在一个SELECT语句中使用多个CTE‘s,假设我有列表3所示的非CTE的查询:
USE AdventureWorks2012;
GO
SELECT SalesPersonID
, SalesYear
, TotalSales
, SalesQuotaYear
, SalesQuota
FROM ( -- First Subquery
SELECT SalesPersonID
, SUM(TotalDue) AS TotalSales
, YEAR(OrderDate) AS SalesYear
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID, YEAR(OrderDate)
) AS Sales
JOIN ( -- Second Subquery
SELECT BusinessEntityID
, SUM(SalesQuota)AS SalesQuota
, YEAR(QuotaDate) AS SalesQuotaYear
FROM Sales.SalesPersonQuotaHistory
GROUP BY BusinessEntityID, YEAR(QuotaDate)
) AS Sales_Quota
ON Sales_Quota.BusinessEntityID = Sales.SalesPersonID
AND Sales_Quota.SalesQuotaYear = Sales.SalesYear
ORDER BY SalesPersonID, SalesYear;
列表3:在一个单独的SELECT语句中使用多个子查询
列表3中的查询包含两个不同的子查询,它们都实现为一个派生表。第一个子查询通过SalesPersonID,SalesYear来计算TotalSales。基于BusinessEntityID 和SalesQuotaYear的聚合值SalesQuota在第二个子查询中被计算。
为了简化阅读列表3中的代码,我们可以将子查询重写为两个不同的CTEs,然后在一个简单的SELECT子句中引用它们,如同我在列表4中所完成的那样:
USE AdventureWorks2012;
GO
-- First Subquery rewritten as CTE
WITH Sales AS
(
SELECT SalesPersonID
, SUM(TotalDue) AS TotalSales
, YEAR(OrderDate) AS SalesYear
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID, YEAR(OrderDate)
),
-- Second Subquery rewritten as CTE
Sales_Quota AS
(
SELECT BusinessEntityID
, SUM(SalesQuota)AS SalesQuota
, YEAR(QuotaDate) AS SalesQuotaYear
FROM Sales.SalesPersonQuotaHistory
GROUP BY BusinessEntityID, YEAR(QuotaDate)
)
-- SELECT using multiple CTEs
SELECT SalesPersonID
, SalesYear
, TotalSales
, SalesQuotaYear
, SalesQuota
FROM Sales
JOIN Sales_Quota
ON Sales_Quota.BusinessEntityID = Sales.SalesPersonID
AND Sales_Quota.SalesQuotaYear = Sales.SalesYear
ORDER BY SalesPersonID, SalesYear;
列表4:使用两个CTE’s来代替子查询
在列表4中我将列表3中的两个子查询移动到两个不同的CTE‘s中。第一个CTE,以名字Sales来进行定义,包含了通过SalesPersonID和SalesYear来产生TotalSales数量的子查询。通过在第一个CTE的后面加上一个逗号,我定义了第二个名为SalesQuota的CTE。第二个CTE包含了子查询以计算其SalesQuota数量。在定义了两个CTE之后我便可以在我最终的SELECT语句中引用它们。
能够在一个单独的WITH子句中定义多个CTE’s,并在最终的T-SQL语句中引用它们,这些特性允许我将我在列表3中的复杂的SQL变得更易阅读,部署以及调试。对于复杂的T-SQL逻辑使用CTE‘s允许你将你的代码分解为可维护的逻辑块或者部分。
To be continued...
【译】高级T-SQL进阶系列 (三)【中篇】:理解公共表表达式(CTEs)的更多相关文章
- 【译】高级T-SQL进阶系列 (三)【上篇】:理解公共表表达式(CTEs)
[译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:传送门. 伴随着SQL SERVER 2005的首次展示,微软介绍了一种新的被称为“公共表 表达式”(CTE)的查询结构. ...
- Bing Maps进阶系列三:使用地图图像服务(ImageryService)
Bing Maps进阶系列三:使用地图图像服务(ImageryService) 地图图像服务(ImageryService)提供了根据地理位置(经度和纬度)坐标和地图的缩放级别解析出对应于地图图片系统 ...
- Spring Boot进阶系列三
Thymeleaf是官方推荐的显示引擎,这篇文章主要介绍怎么让spring boot整合Thymeleaf. 它是一个适用于Web和独立环境的现代服务器端Java模板引擎. Thymeleaf的主要 ...
- SQL进阶系列之9用SQL处理数列
写在前面 关系模型的数据结构里,并没有顺序的概念,但SQL处理有序集合也有坚实的理论基础 生成连续编号 --生成连续编号 CREATE TABLE Digits (digit INTEGER PRIM ...
- SQL进阶系列之7用SQL进行集合运算
写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...
- SQL进阶系列之5外连接的用法
写在前面 SQL本身是作为一种数据提取工具而出现,使用SQL生成各种定制化报表和非定制化报表并非SQL原本用途的功能,但这并不意味着SQL无法实现这些功能. 用外连接进行行列转换(1)(行 → 列): ...
- SQL进阶系列之3三值逻辑与NULL
写在前面 普通编程语言里的布尔型只有true和false两个值,这种逻辑体系被称为二值逻辑,而SQL语言里,还有第三个值unknown,因此SQL的逻辑体系被称为三值逻辑. Why SQL存在三值逻辑 ...
- 进阶系列三【绝对干货】----Log4.Net的介绍
一.介绍 当我们开发软件时,一般都会加入运行期的跟踪手段,以方便后续故障分析和Bug调试..net framework本身提供了一个System.Diagnostics.Trace类来实现流程跟踪功能 ...
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...
随机推荐
- t-SNE
Don't look back. Don't hesitate, just do it. t-SNE原理 from here. 1. tsne is strictly used for visuali ...
- 利用python装饰器为字符串添加,HTML标签
# 为字符串添加HTML标签 import time def zhuang(fun): def zhaung_1(*args, **kargs): # time.sleep(1) html_str = ...
- 同步循环发请求用promise
function ajax(image, ind) { return new Promise(function(resolve, resject) { setTimeout(fu ...
- Explainable ML
定义: 不仅可以(分类),还要输出分类的理由是什么(局部),以及某一个分类的判断标准(全局) 局部: silence map. 把{x1.....xn}中每一个像素加一个偏移量之后,得到的y偏移量与x ...
- php:对象(object)数据类型实例详解
什么是对象? 对象是存储数据和有关如何处理数据的信息的数据类型.是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位.一个对象由一组属性和对这组属性进行操作的一组服务组成. 语法 在 PHP ...
- D. Mahmoud and Ehab and another array construction task 因子分界模板+贪心+数学
D. Mahmoud and Ehab and another array construction task 因子分解模板 题意 给出一个原序列a 找出一个字典序大于a的序列b,使得任意 \(i!= ...
- 常用的MQ命令
删除队列管理器 dltmqm QmgrName 启动队列管理器 strmqm QmgrName 如果是启动默认的队列管理器,可以不带其名字 停止队列管理器 endmqm QmgrName 受控停止 e ...
- 1.BMap(百度地图)第二次加载显示不全
问题: bmap第一次加载显示没问题: 第二次 再次加载这个页面时,地图的显示出现了问题: . 分析问题出现原因:你要确保dom创建后且处于显示状态(即display不能为none)才能再次初始化地图 ...
- CDH的坑之Deploy Client Configuration Failed
Deploy Client Configuration Failed 1.问题描述 当使用CDH增添spark服务的时候,出现了以下错误: Faile to deploy client configu ...
- Docker镜像加速,设置国内源
源地址设置 在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件) { "registry-mirrors": [ "https ...