通往t - sql的阶梯:超越基本级别2:编写子查询sql
格雷戈里·拉森(Gregory Larsen),2016/01/01(第一次出版:2014 /01/ 29)数据库
该系列函数
这篇文章是楼梯系列的一部分:通往t - sql的楼梯:超越基础。工具
从他的阶梯到t - sql DML,Gregory Larsen涵盖了t - sql语言的更高级的方面,如子查询。sqlserver
在开始建立比基本transact - SQL语句更复杂的SQL代码时,您可能会发现须要使用其余SELECT语句的结果来约束您的查询。当您在父transact - sql语句中嵌入SELECT语句时,这些嵌入的SELECT语句被称为子查询或相关子查询。在这个层次的基础上,我将讨论子查询的不一样方面,在之后的级别中,我将讨论相关的子查询。性能
子查询是什么?测试
子查询只是在另外一个transact - sql语句中包含的SELECT语句。能够在任何可使用表达式的地方使用子查询。许多子查询返回单个列值,由于它们与比较运算符一块儿使用(=,!=,< =,>,> =)或表达式。当子查询不用做表达式或与比较运算符使用时,它能够返回多个值。此外,子查询甚至能够返回多个列和值,当它们在FROM子句或关键字中使用时。优化
在transact - sql语句中很容易发现子查询,由于它将是括号中包含的SELECT语句。因为子查询包含在transact - sql语句中,子查询一般被称为内部查询。而包含子查询的transact - sql语句被称为外部查询。子查询的另外一个特性是,它能够独立于外部查询运行,而且将运行没有错误,而且可能返回一组行,或者返回一个空行集。spa
子查询的另外一种形式是相关子查询。可是关联子查询不能独立于外部Transact SQL语句运行。关联子查询使用来自外部查询的列或列来约束从相关子查询返回的结果。对于本文的相关子查询,这已经足够了。我将在将来的楼梯文章中探索相关的子查询。3d
如下是使用子查询时须要考虑的其余事项:
•ntext、文本和图像数据类型不容许从子查询返回
•除非使用顶部运算符,不然不能在子查询中使用ORDER BY子句
•使用子查询的视图不能更新
•在子查询中不能使用compute和INTO子句
子查询示例的示例数据
为了演示如何使用子查询,我须要一些测试数据。个人全部示例都将使用AdventureWorks2008R2数据库,而不是建立本身的测试数据。若是您想要跟随并运行我在您的环境中的示例,那么您能够从这里下载AdventureWorks2008R2数据库:
http://msftdbprodsamples.codeplex.com/releases/view/93587
返回单个值的子查询示例
如上所述,在比较操做符的一侧使用表达式或返回值的子查询须要返回一个值。transact - sql语句中有许多不一样的地方须要子查询返回一个列值,就像在一个选择列表,where子句,等等。在本节中,我将提供一系列的例子将演示使用子查询表达式或比较运算符,以知足不一样的业务需求。
子查询列列表中
列表中的子查询是一个SELECT语句,它返回SELECT子句的列列表中的单个列值。为了演示如何在选择列表中使用子查询,咱们假设必须从SELECT语句中生成一个具备如下业务需求的结果集:
•归还全部的销售。SalesOrderHeader记录了一个订单日期等于“2007 -02-19 00:00. 00”
•按SalesOrderID顺序订购返回的记录
•每一行返回最古老的顺序的行数为1的行数,下一个最大的行数为2,等等
•结果集须要一个名为TotalOrders的列,该列须要填满整个订单的数量,该订单的订单数量等于“2007 -02-19 00:00. 00”
知足这些需求的代码如清单1所示。
清单1:列列表中的子查询
在这个transact - sql语句中,您能够看到两个不一样的SELECT子句。子查询是在清单1的语句中嵌入的SELECT语句,它周围有括号。我已经提取了子查询语句并将其放入清单2中,以防您想要测试验证它是否能够独立于完整的transact - sql语句运行。
清单2:在清单1中找到的子查询语句
经过在列列表中拥有这个子查询,Listing1中的transact - sql语句可以计算有一个OrderDate“2007 -02-19 00:00. 000”的SalesOrderHeader行的数量,并返回该信息以及关于销售的详细行信息。有相同的OrderDate值的SalesOrderHeader记录。
子查询在WHERE子句中的例子
有时您但愿根据SELECT语句的结果来驱动WHERE子句条件。当您在WHERE子句中选择语句时,这个SELECT语句其实是一个子查询。为了演示在WHERE子句中使用子查询,假设您须要显示销售。SalesOrderDetail记录包含购买超大的长袖标志运动衫。清单3中的代码使用子查询知足个人显示需求。
清单3:WHERE子句中的子查询
清单3中的子查询位于WHERE条件的右侧。这个子查询标识生产的产品。产品名称的产品名称为“长袖标志球衣,XL”。这个子查询容许我找到全部的销售。SalesOrderDetail记录有一个与“长袖Logo Jersey,XL”的产品名称相关的产品。
示例使用子查询来控制TOP子句
使用TOP子句返回的行数能够由表达式控制。清单5中的代码标识了销售数量。SalesOrderDetail行应该基于顶部子句中的子查询返回。
清单4:TOP子句中的子查询
清单4中的代码使用从子查询返回的OrderQty值来标识将在TOP子句中使用的值。经过使用子查询来控制TOP子句返回的行数,能够建立一个子查询,该子查询将动态识别在运行时从查询返回的行数。
子查询在HAVING子句中的例子
为了演示在“有”子句中使用子查询,假设您有如下业务需求:
生成包含sales . salesorderheader的结果集。订单日期和每一个日期的订单数量,其中订单数量超过了“2006 -05- 01”的订单数量。
为了知足这一要求,我已经开发了清单6中的查询,其中使用了“HAVING子句”中的子查询。
清单5:HAVING子句中的子查询
清单5中的代码在有子句的右边有子查询,并在个人子查询中使用COUNT函数来肯定在“2006-05-01”上放置的订单数量。
在函数调用中使用子查询的例子
为了演示在函数调用中使用子查询,假设您有要求在OrderDate和每一个Sales的最大OrderDate之间显示天数。SalesOrderHeader记录。清单6中的代码知足这一需求。
清单6:函数调用中的子查询
清单6中的代码有两个不一样的子查询。两个子查询都返回Sales中的max OrderDate。SalesOrderHeader表。可是,第一个子查询用于将日期传递给DATEDIFF函数的第二个参数。
返回多个值的子查询示例
到目前为止,个人全部示例都包含子查询,这些子查询仅在单个列中返回单个值。并非全部的子查询都有这样的要求。接下来的几个示例将使用返回多个值和/或多个列的子查询。
子查询在FROM子句中的示例
在FROM子句中,您一般肯定您的transact - sql语句将针对的表或表集合。每一个表提供一组记录,您的查询将使用这些记录来肯定您的查询的最终结果集。子查询能够看做是返回一组记录的查询,所以它能够像表同样在FROM子句中使用。清单7中的查询显示了我如何在FROM子句中使用子查询。在FROM子句中使用子查询时,子查询生成的结果集一般称为派生表。
清单7:FROM子句中的子查询
清单7中的代码使用FROM子句中的子查询建立一个表别名,名为Last10SalesOrders。个人子查询返回了最后10个销售。alesOrderDetail记录包含一个716的产品。
在清单7中,个人代码是一个很是简单的例子,说明如何在FROM子句中使用子查询。经过使用FROM子句中的子查询,您能够轻松地从语法中构造出更复杂的代码,这些语法将与其余表的子查询结果链接起来,或者添加其余子查询,如清单8所示。
清单8:加入一个有实表的派生表
在清单8中,我使用了在清单7中建立的子查询/派生表,并将它与SalesOrderHeader表链接起来。经过这样作,我能够肯定一个不一样的订单日期,这是最后10次人们订购的产品= 716。
使用IN关键字进行子查询的示例
另外一个能够编写子查询的地方,该子查询返回一个列的多个值,当子查询生成一个用于关键字的记录集时。清单9中的代码演示了如何使用子查询将值传递到in关键字。
清单9:使用子查询将值传递到IN关键字
清单9中的代码使用子查询返回产品的不一样值。包含字符“XL”的产品表。这些从子查询返回的ProductID值而后在in关键字中使用,以约束从销售中返回的行。SalesOrderDetail表。
在修改数据的语句中使用子查询的例子
到目前为止,个人全部示例都演示了如何在SELECT语句的不一样部分中使用子查询。子查询也能够在插入、更新或删除语句中使用。清单10中的代码展现了如何在INSERT语句中使用子查询。
清单10:插入语句中的子查询
在清单10的代码中,我使用子查询来计算插入到列MaxOrderDate中的值。这仅仅是如何在INSERT语句中使用子查询的一个示例。请记住,子查询也能够在UPDATE和/或DELETE语句中使用。
子查询与链接之间的性能考虑
若是你读过微软生产的“子查询基础”文档(http://technet.microsoft.com/en-us/library/ms189575(v=sql.105).aspx)
而后,您可能遇到了关于包含子查询的语句的性能的语句:
“在transact - sql中,包含子查询和语义等价的语句之间一般没有性能差别。”
为了比较使用子查询和不使用子查询的查询的性能,我将重写清单3中的子查询以使用链接操做。清单11显示了我从新编写的JOIN查询,它至关于清单3中的查询。
清单11:链接查询,与清单3中的查询等效
为了比较清单3中使用子查询的查询的性能和使用JOIN的清单11中的查询,我将使用清单12中的代码运行两个查询。
清单12:测试清单3和清单4的性能的代码
在运行清单12中的代码后,我查看了由“SET STATISTICS”语句生成的消息。经过查看统计数据,我发现两个查询对SalesOrderDetail表有3,309个逻辑读取,2个逻辑读针对产品表,每一个都使用31毫秒的CPU。另外,我回顾了为这两个查询建立的SQL Server的执行计划。我发现SQL Server对这两种状况都产生了相同的执行计划。所以,在个人状况下使用子查询或链接查询产生等价的性能,就像微软所记录的那样。
总结
子查询是嵌入另外一个transact - sql语句的SELECT语句。子查询能够独立于外部查询运行,所以有时被称为独立查询。请记住,每当有一个子查询替表明达式时,或者它与比较运算符一块儿使用,它只能返回单个列和值。一般可使用JOIN逻辑重写子查询。子查询是帮助您构建更复杂的transact - sql语句以知足业务需求的强大工具。
问题和回答
在本节中,您能够经过回答如下问题来回顾您如何理解使用子查询概念。
问题1:
完成这个句子“子查询是在另外一个transact - sql语句中选择语句,它是_____________________”。
•不能独立于完整的查询运行。
•引用来自外部查询的列。
•当独立于外部查询运行时,它将返回结果。
问题2:
子查询什么时候只须要返回一个列和值(选择全部应用程序)?
•当子查询在FROM子句中使用时
•当子查询在in子句中使用时
•在表达式中使用子查询
•当子查询与比较运算符一块儿使用时
问题3:
在WHERE子句中使用子查询的transact - sql语句老是比不包含子查询(True或False)的等价查询执行速度慢。
•真
•假
回答:
问题1:
正确的答案是c。子查询能够独立于外部查询运行,它将返回结果。它不须要来自外部查询的任何列,若是它有来自外部查询的列,则称为相关子查询。
问题2:
正确的答案是c和d。子查询须要返回一个列值,当它用做表达式时,或者在比较操做中。当在关键字中使用子查询时,它能够为一列返回一个或多个值。若是在FROM子句中使用子查询,它只返回一个列和一个值,但它也能够返回多个列和值。
问题3:
正确的答案是错误的。SQL Server优化器很是聪明,极可能会为两个等价查询计算相同的执行计划。若是一个查询的执行计划包含一个子查询,而没有子查询的查询的执行计划最终都有相同的执行计划,那么这两个查询将具备相同的性能。
连接:http://www.sqlservercentral.com/articles/Stairway+Series/104517/