【译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正】

原文连接:传送门

当一个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记录,那么QtyTotalSalesAmt 值便会被关联在期望的行中。这个查询做的最后一件事便是使用GROUP BY子句来基于SalesDate和ProductName来对Qty 和TotalSalesAmount 进行总结。

最新文章

  1. Visual studio 通用开发环境配置:SDL,FFMPEG为例
  2. Struts2核心技术简介
  3. Mysql 事件(定时任务)
  4. linux命令合集
  5. 【转】getopt分析命令行参数
  6. 利用servlet做转发,实现js跨域解决同源问题
  7. 实现一个线程安全的Queue队列
  8. javascript中的变量作用域
  9. JQuery中的省市联动
  10. WebSphere优化
  11. shell 实例学习
  12. linux下PHP 环境搭建
  13. 爬取西刺网代理ip,并把其存放mysql数据库
  14. [Swift]LeetCode300. 最长上升子序列 | Longest Increasing Subsequence
  15. python 全栈开发笔记 1
  16. 小白入门使用Nginx基础的常用操作
  17. 【交换机】交换机RLDP(环路检测&链路检测)功能介绍及配置说明
  18. MEAN 27
  19. this引用逃逸(使用内部类获取未外部类未初始化完的变量),多态父类使用子类未初始化完的变量
  20. Mybatis中Mapper的Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?

热门文章

  1. linux下修改mysql的编码格式
  2. 安卓按键:读取txt开头出现未知字符的问题
  3. 手动搭建的react环境中,关于图片引入的问题
  4. 接入HikariCP遇到问题
  5. Java - Java 命令行简介: 选项, 属性, 参数
  6. Yii2 的 updateAll 方法参数详解
  7. Laravel 解决在ajax 请求下不能保存session的问题
  8. List 线性表:ArrayLis,LinkedList
  9. 红帽RHCE培训-课程3笔记目录
  10. Django框架之ORM的相关操作(一)