高级T-SQL进阶系列 (一)【中篇】:使用 CROSS JOIN 介绍高级T-SQL
【译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正】
原文连接:传送门。
当一个CROSS JOIN 表现得如同一个INNER JOIN
在上一章节我提到当你使用一个CROSS JOIN 操作符时候它会产生一个笛卡尔积。然而这并不总是真实的情况。当你使用WHERE 子句对涉及到CROSS JOIN操作符的表的关联进行约束,SQL SERVER便不会产生笛卡尔积。反而它的功能更像是一个正常的 JOIN 操作符。为了演示这种行为,请查看列表5的代码:
SELECT * FROM Product P CROSS JOIN SalesItem S
WHERE P.ID = S.ProductID;
SELECT * FROM Product P INNER JOIN SalesItem S
ON P.ID = S.ProductID;
列表5:两个相等的SELECT语句
列表5的代码包含了两个SELECT语句。第一个语句使用了CROSS JOIN操作符然后使用了一个WHERE子句来定义如何连接CROSS JOIN操作符涉及的两个表。第二个SELECT语句使用了带有一个ON子句的正常的INNER JOIN操作符来关联两个表。SQL SERVER的查询优化器足够智能,可以知道列表5中的第一个SELECT语句可以重写为一个INNER JOIN。一个WHERE子句在此提供了CROSS JOIN操作符涉及的两个表的连接谓词,因此当一个CROSS JOIN操作符和一个WHERE子句配合起来使用的时候,查询优化器便知道它可以重写这个查询。因此SQL SERVER引擎为列表5中的两个查询生成了相同的执行计划。而当你不提供一个WHERE约束的时候,SQL SERVER不知道如何关联CROSS JOIN子句涉及的两个表,于是便在CROSS JOIN操作符相关的两个数据集之间创建了笛卡尔积。
使用CROSS JOIN来找到未卖出的产品
前面章节出现的示例可以帮助你理解CROSS JOIN操作符以及如何使用它。使用CROSS JOIN操作符的力量之一便是用其找到存在于一个表而在另一张表中没有匹配记录的那些条目。举个例子,假设我想要报告Product表中的每个产品每天的销售量和销售金额,因为在我的例子中,每个ProductName每天没有被销售也会有一个记录。我的报告需求意味着我需要为那些在某一个给定的日期中没有销售的产品展示一个数量0和销售金额为0的记录。而CROSS JOIN操作符与LEFT OUTER JOIN操作符配合起来使用恰好可以帮助我定义这些在某一天没有售出的条目。满足这些报告需求的代码可以在列表6中被找到:
SELECT S1.SalesDate, ProductName
, ISNULL(Sum(S2.Qty),0) AS TotalQty
, ISNULL(SUM(S2.TotalSalesAmt),0) AS TotalSales
FROM Product P
CROSS JOIN
(
SELECT DISTINCT SalesDate FROM SalesItem
) S1
LEFT OUTER JOIN
SalesItem S2
ON P.ID = S2.ProductID
AND S1.SalesDate = S2.SalesDate
GROUP BY S1.SalesDate, P.ProductName
ORDER BY S1.SalesDate;
列表6:使用CROSS JOIN找到没有销售的产品
让我来带你分析这段代码。首先我创建了一个子查询,它获取了所有去重的SalesDate的值。这个子查询给了我所有发生交易的日期。然后我用Product表与其进行CROSS JOIN,这允许我在每个日期和每种产品行之间创建一个笛卡尔积。从CROSS JOIN返回的数据集将会包含我在最终结果集合中需要的每个值--当然除了每个售出产品的Qty和TotalSalesAmt 。为了得到这些汇总列我将CROSS JOIN得到的笛卡尔积与SalesItem表进行了一个LEFT OUTER JOIN关联。我基于ProductID和ProductID列进行了这个关联。通过使用LEFT OUTER JOIN,笛卡尔积中的每一行数据都会被返回,并且如果对于一个ProductID和SalesDate具有一个匹配的SalesDate记录,那么Qty和TotalSalesAmt 值便会被关联在期望的行中。这个查询做的最后一件事便是使用GROUP BY子句来基于SalesDate和ProductName来对Qty 和TotalSalesAmount 进行总结。
高级T-SQL进阶系列 (一)【中篇】:使用 CROSS JOIN 介绍高级T-SQL的更多相关文章
- 高级T-SQL进阶系列 (一)【上篇】:使用 CROSS JOIN 介绍高级T-SQL
[译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文连接:传送门 这是一个新进阶系列的第一篇文章,我们将浏览Transact-SQL(T-SQL)的更多高级特性.这个进阶系列将会包 ...
- 高级T-SQL进阶系列 (一)【下篇】:使用 CROSS JOIN 介绍高级T-SQL
[译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:传送门. 性能考虑产生了笛卡尔积的这个CROSS JOIN操作符具有一些性能方面的问题需要考虑.因为SQL引擎需要将一个数 ...
- SQL进阶系列之7用SQL进行集合运算
写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...
- SQL进阶系列之9用SQL处理数列
写在前面 关系模型的数据结构里,并没有顺序的概念,但SQL处理有序集合也有坚实的理论基础 生成连续编号 --生成连续编号 CREATE TABLE Digits (digit INTEGER PRIM ...
- SQL进阶系列之8EXISTS谓词的用法
写在前面 支撑SQL和关系数据库的基础理论:数学领域的集合论和逻辑学标准体系的谓词逻辑 理论篇 什么是谓词?谓词是返回值为真值(true false unknown)的函数 关系数据库里,每一个行数据 ...
- SQL进阶系列之5外连接的用法
写在前面 SQL本身是作为一种数据提取工具而出现,使用SQL生成各种定制化报表和非定制化报表并非SQL原本用途的功能,但这并不意味着SQL无法实现这些功能. 用外连接进行行列转换(1)(行 → 列): ...
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...
- SQL进阶系列之12SQL编程方法
写在前面 KISS -- keep it sweet and simple 表的设计 注意命名的意义 英文字母 + 阿拉伯数字 + 下划线"_" 属性和列 编程的方针 写注释 注意 ...
- SQL进阶系列之10HAVING子句又回来了
写在前面 HAVING子句的处理对象是集合而不是记录 各队,全队点名 --各队,全体点名! CREATE TABLE Teams (member CHAR(12) NOT NULL PRIMARY K ...
随机推荐
- 小程序websocket用法
// socket已经连接成功 var socketOpen = false // socket已经调用关闭function var socketClose = false // socket发送的消 ...
- 解决Cannot download "https://github.com/sass/node-sass/releases/download/binding.nod的问题
npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
- Kali国内源更新sources.list
Kali国内源更新sources.list 更新源,个人推荐中科大leafpad /etc/apt/sources.list #中科大 deb http://mirrors.ustc.ed ...
- Comparable
为什么会有Comparable与Comparator接口? 引入策略模式 目录 引入 Comparable接口的来龙去脉 引入Comparator接口 什么是策略模式? 使用了策略模式有什么好处? ...
- 一张linux光盘查看是哪个版本号的方法
在此查看版本号,方法如下:打开光盘,查找rpm包中的release,就是版本号.
- <img>标签在vue中的使用
定义和用法 onerror 事件会在文档或图像加载过程中发生错误时被触发. 在装载文档或图像的过程中如果发生了错误,就会调用该事件句柄. 实例 加载缩略图 <img :src="'/x ...
- 《实战Java高并发程序设计》读书笔记一
第一章 走入并行世界 1.基本概念 同步:同步方法一旦开始,调用者必须等到方法调用返回后,才能继续后续操作 异步:一旦开始,方法调用就会立即返回,调用就可以继续后续操作 并发:表示两个或者多个任务一起 ...
- Java面向对象编程 -4.3
static应用实例 编写一个程序类,这个类可以实现实例化对象个数的统计,每次创建的实例化对象都可以实现一个统计操作. 此时可以单独创建一个static属性,因为所有对象都共享同一个static属性, ...
- mcast_get_ttl函数
#include <errno.h> #include <net/if.h> #include <sys/socket.h> #include <netine ...
- A Kill Cord for your Laptop
前言 昨晚在朋友圈看到国外一篇文章利用U盘锁笔记本电脑,刚好有一个坏的金士顿U盘,所以就折腾了一下. 准备 USB设备*1 Arch系统*1 走过的坑 因为systemd-udevd带起来的进程是ro ...