设为首页 加入收藏

TOP

阶梯到高级T-SQL 1级:高级T-SQL介绍交叉连接(二)
2018-05-08 06:06:55 】 浏览:426
Tags:阶梯 高级 T-SQL 介绍 交叉 连接
CAST(SalesItem.ID asvarchar(2))ASProductName,

(Product.Cost /SalesItem.ID)*100 ASCostFROMProduct CROSSJOINSalesItem;

清单3:简单的交叉连接例子

当我运行清单3中的代码时,获得Report 2中的输出。

ID ProductName Cost

----- ----------------------------------------------------------- ---------------------

1 Widget1 2199.00

2 Widget2 1099.50

3 Widget3 733.00

4 Widget4 549.75

5 Widget5 439.80

6 Watchamacallit1 196.00

7 Watchamacallit2 98.00

8 Watchamacallit3 65.33

9 Watchamacallit4 49.00

10 Watchamacallit5 39.20

11 Thingamajig1 538.00

12 Thingamajig2 269.00

13 Thingamajig3 179.33

14 Thingamajig4 134.50

15 Thingamajig5

Report2:;运行清单3的结果

正如您可以看到的,通过查看清单3中的代码,我生成了许多行,其中包含类似于我的Producttable中的数据的数据。通过使用ROW_Number函数,我能够在每一行上生成唯一的ID列。此外,我还使用Salesltem表中的ID列来创建唯一的ProductName和成本列值。生成的行数等于Producttable中的行数乘以Salesltem表中的行数。

到目前为止,本节中的示例只对两个表执行了交叉连接。您可以使用交叉连接操作符来跨多个表执行交叉连接操作,清单4中的例子将在三个表中创建一个笛卡儿管道。

SELECT*FROMsys.tables CROSSJOINsys.objectsCROSSJOINsys.sysusers;

清单4:使用交叉连接操作符创建三个表的笛卡尔

运行清单4的输出有两个不同的交叉_连接操作。从这段代码创建的笛卡尔产品将产生一个结果集,其总行数等于sys.table中行数的J乘以sys.objects中的行数。

当交叉连接像内部连接一样执行时

在前面的部分,我提到当你使用交叉连接算子时,它会产生笛卡儿乘积。这不是一直都是这样的。当您使用限制交叉连接操作中涉及的表的联接的WHERE子句时,SQLServer不会创建笛卡尔产品。相反,它的功能类似于普通的联接操作。要演示这种行为,请查看代码在清单5。

SELECT*FROMProduct P CROSSJOINSalesItem SWHEREP.ID =S.ProductID;

SELECT*FROMProduct P INNERJOINSalesItem SONP.ID =S.ProductID;

清单5:两个等价的SELECT语句

清单5中的代码包含两个SELECT语句。第一个SELECT语句使用交叉连接操作符,然后使用WHERE子句定义如何连接在交叉连接操作中开具发票的两个表。第二个SELECT语句使用一个普通的带有ON子句的内部Jojn操作符来连接这两个表。SQLServer的查询优化器非常聪明,可以知道清单5中的第一个SELECT语句可以重写为内部联接。当交叉连接操作与WHERE子句一起使用时,优化器知道可以重写查询。WHERE子句在交叉连接所涉及的两个表之间提供连接谓词。因此,SQLSener引擎为清单5中的两个SELECT语句生成相同的执行计划。当您不提供WHERE约束时,SQLServer不知道如何加入涉及交叉连接操作的两个表,因此它在与交叉连接关联的两个集合之间创建一个笛卡儿积。

 

用交叉连接找出未销售产品

在前面章节中的例子有助于你理解CROSS JOIN 操作并且理解如何使用它。CROSS JOIN运算符的一个功能是用它来在另一个表中帮助查找一个表中没有匹配记录的项。例如,假设在我的产品表中列出了我的任何一个产品的销售日期我想要报告总数量和总销售额对每个产品名称。因为在我的例子中产品名称不是每天都有销售,我的报告要求意味着我需要展示在给定日期没销售的产品的数量0和销售总额0美元。交叉联接运算符与左外部联接操作一起在这将帮助我识别那些在给定日期内尚未销售的产品。6中可以找到满足这些报告要求的代码:

SELECTS1.SalesDate,ProductName

,ISNULL(Sum(S2.Qty),0)ASTotalQty

,ISNULL(SUM(S2.TotalSalesAmt),0)ASTotalSales

FROMProduct P

CROSSJOIN

(

SELECTDISTINCTSalesDate FROMSalesItem

)S1

LEFTOUTERJOIN

SalesItem S2

ONP.ID =S2.ProductID

ANDS1.SalesDate =S2.SalesDate

GROUP BYS1.SalesDate,P.ProductName

ORDERBYS1.SalesDate;

让我通过这个代码向你介绍。我创建一个子查询来选择所有不同的销售日期值。此子查询提供了销售的所有日期。然后交叉加入我的产品表。这允许我创建一个Cartesian在销售日期每一个结果行之间。从交叉联接返回的集合有我需要的所有值将在最终结果集中除了Qty的和和销售总额每售出一件产品。为了获得这些值我用笛卡尔积操作和一个左侧外连接来得到销售项目表。我是根据产品编号和销售日期列。通过使用左外部联接,将返回我的笛卡尔乘积中的每一行,如果匹配销售日期的记录产品编号和销售日期,问总产量和销售总额值将与适当的行相链接。这个查询的最后一件事是使用GROUP BY子句来总结数量和销售总额基于销售日期和产品名称。

性能考虑

生成笛卡尔乘积的交叉连接运算符需要考虑一些性能方面。因为SQL引擎需要将加入一个集合的每一行与另一个集结果集可能会很大。如果将一个具有1000000行的表与另一个具有100000行的表交叉连接,则我的结果集将具有1000000 X 100000行,即100000000行。这是一个很大的结果集,需要花费SQL Server大量的时间去创建。

CROSS JOIN操作可以是一个很好的解决方案,对于识别两个集合的所有可能组合中的一个结果集,像每个月所有客户的所有销售一样,即使有些客户有几个月没有销售。当使用交叉连接运算符时,你应尽量减小交叉连接的集的大小如果要优化性能。例如,假设我有一个表,其中包含过去2个月的销售数据。如果我想生成一个显示一个月内没有任何销售的客户的报告,那么确定一个月内天数的方法可以极大地改变我的查询。为了证明这一点,首先让我为1000名客户创建一组为期两个月的销售记录。我将使用7中的代码执行此操作。

CREATETABLECust (Id int,CustName varchar(20));

CREATETABLESales (Id intidentity

,CustID int

,SaleDate date

,Sales

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Mybatis报错TranslatingSQLExcept.. 下一篇oracle系列基础之级联删除和级联..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目