原文连接:http://www.sqlservercentral.com/articles/Stairway+Series/104517/sql
经过格雷戈里·拉森,2016/01/01(第一次出版:2014/01/29)数据库
在某些时候当你开始建立更复杂的SQL代码,超越基本transact - SQL语句,您可能会发现须要限制你的查询使用其余SELECT语句的结果。 当你在父母transact - sql语句嵌入一个SELECT语句,这些嵌入的SELECT语句被称为子查询,或相关子查询。 在本层的楼梯的基本内容外,我将讨论子查询的不一样方面,在将来我将讨论相关子查询。sqlserver
子查询是一个SELECT语句是包含在数据库引擎执行另外一个sql语句。 可使用子查询可使用任何一个表达式。 许多子查询返回一列值,由于他们结合使用比较运算符(=,! =、<、< =、>、> =),或者一个表达式。 当不使用子查询表达式或比较运算符能够返回多个值。 此外,子查询能够返回多个列和价值观在FROM子句中使用或与关键字的存在。性能
数据库引擎执行子查询是容易被发如今一个sql语句,由于它将SELECT语句包含在圆括号中。 因为数据库引擎执行子查询包含在一个sql语句查询一般被称为内部查询。 而transact - sql语句包含子查询被称为外部查询。 子查询的另外一个特色是它能够独立运行的外部查询和运行没有错误,并可能返回的一组行,或一个空行。测试
另外一种形式的子查询是相关子查询。 但相关子查询不能独立运行的外部交易的SQL语句。 相关子查询使用列或列从外部查询限制相关子查询返回的结果。 这是对这篇文章的相关子查询。 我将探索相关子查询在之后的楼梯。优化
这里有一些其余的事情时要考虑使用子查询:spa
为了演示如何使用子查询我须要一些测试数据。 而不是建立我本身的测试数据,我全部的例子将使用AdventureWorks2008R2数据库。 若是你想跟随并运行在您的环境中个人例子你能够下载AdventureWorks2008R2数据库从这里:http://msftdbprodsamples.codeplex.com/releases/view/93587code
如上所述,子查询中使用一个表达式或返回一个值比较运算符的一侧必须返回一个值。 transact - sql语句中有许多不一样的地方须要子查询返回一个列值,就像在一个选择列表,where子句,等等。在本节中,我将提供一系列的例子将演示使用子查询表达式或比较运算符,以知足不一样的业务需求。
子查询的列列表是一个SELECT语句返回一列值的列列表放置在一个SELECT子句。 为了演示如何使用选择列表的子查询假设咱们必须从一个SELECT语句产生一个结果集,如下业务需求:
知足这些需求的代码如清单1所示。
SELECT ROW_NUMBER() OVER (ORDER BY SalesOrderID) RowNumber , (SELECT COUNT(*) FROM [Sales].[SalesOrderHeader] WHERE ModifiedDate = '2007-02-19 00:00:00.000') AS TotalOrders , * FROM [Sales].[SalesOrderHeader] WHERE OrderDate = '2007-02-19 00:00:00.000';
在这个单一transact - sql声明中看到两个不一样的选择条款。 子查询的SELECT语句嵌入在清单1,括号中的语句。 我拿出了子查询语句和把它在清单2中,若是您想测试来验证它能够独立完成transact - sql语句的运行。
SELECT COUNT(*) FROM [Sales].[SalesOrderHeader] WHERE OrderDate = '2007-02-19 00:00:00.000'
清单2:子查询语句中找到清单1所示
经过这个子查询的列列表,这Listing1 transact - sql语句可以数的数量SalesOrderHeader行,一个向数据库“2007-02-19 00:00:00.000”和返回的信息以及详细的行信息Sales.SalesOrderHeader有相同的记录向数据库价值。
有时你想开车WHERE子句条件基于一个SELECT语句的结果。 当你一个SELECT语句的WHERE子句这个SELECT语句是一个真正的子查询。 为了演示在WHERE子句中使用子查询,假设你须要显示Sales.SalesOrderDetail记录包含购买超大长袖商标运动衫。 清单3中的代码使用子查询知足个人显示要求。
SELECT * FROM [Sales].[SalesOrderDetail] WHERE ProductID = (SELECT ProductID FROM [Production].[Product] WHERE Name = 'Long-Sleeve Logo Jersey, XL');
清单3:子查询的WHERE子句
清单3中的查询是在右边的条件。 这个子查询标识一个ProductID对于一个Production.Product记录在哪里的名字的产品是“长袖标志的球衣,XL。 这个子查询容许我发现全部的Sales.SalesOrderDetail记录,有ProductID与产品名称相关联的“长袖标志的球衣,XL”。
返回的行数使用上面的条款能够控制的一个表达式。 清单5中的代码标识的数量Sales.SalesOrderDetail行应该返回基于子查询的条款。
SELECT TOP (SELECT TOP 1 OrderQty FROM [Sales].[SalesOrderDetail] ORDER BY ModifiedDate) * FROM [Sales].[SalesOrderDetail] WHERE ProductID = 716;
清单4:子查询最佳条款
清单4中的代码使用OrderQty子查询返回的值来标识的值将用于条款。 经过使用子查询控制返回的行数,上面条款,容许您动态构建子查询,肯定在运行时从查询返回的行数。
为了演示使用子查询子句,假设你有如下业务需求:
产生一个结果集,其中包含了Sales.SalesOrderHeader.OrderDate每一个日期和订单的数量,订单的数量超过了订单的数量了‘2006-05-01’。
为了达到这个要求我开发了清单6中的查询中使用子查询子句。
SELECT count(*), OrderDate FROM [Sales].[SalesOrderHeader] GROUP BY OrderDate HAVING count(*) > (SELECT count(*) FROM [Sales].[SalesOrderHeader] WHERE OrderDate = '2006-05-01 00:00:00.000');
清单5:子查询的条款
清单5中的代码的子查询右边有条款和使用计数函数在子查询来肯定订单的数量在“2006-05-01”。
为了演示在函数调用中使用子查询,假设您有要求显示之间的天数向数据库和最大向数据库为每个销售。SalesOrderHeader记录。 清单6中的代码知足这个需求。
SELECT SalesOrderID , OrderDate ,DATEDIFF ( dd,OrderDate ,(SELECT MAX(OrderDate) FROM [Sales].[SalesOrderHeader]) ) AS DaysBetweenOrders ,(SELECT MAX(OrderDate) FROM [Sales].[SalesOrderHeader]) AS MaxOrderDate FROM [Sales].[SalesOrderHeader];
清单6:在函数调用子查询
清单6中的代码有两个不一样的子查询。 两个子查询返回的马克斯向数据库在Sales.SalesOrderHeader表。 但第一子查询是用来传递一个日期DATEDIFF函数的第二个参数。
到目前为止,我全部的例子包含子查询只返回一个值在一个列中。 并非全部的子查询需求。 接下来的几个例子将使用子查询返回多个值和/或多个列。
在FROM子句一般肯定一个表或一组表,你transact - sql语句将对运做。 每一个表提供了一组记录您的查询将使用来肯定最终的查询结果集。 子查询能够被认为是一个查询,返回一组记录,所以它能够用于从条款就像一张桌子。 查询我在清单7显示了如何使用子查询的FROM子句。 子查询时FROM子句中使用子查询的结果集生产一般被称为一个派生表。
SELECT SalesOrderID FROM (SELECT TOP 10 SalesOrderID FROM [Sales].[SalesOrderDetail] WHERE ProductID = 716 ORDER BY ModifiedDate DESC) AS Last10SalesOrders;
清单7:子查询的FROM子句
SELECT DISTINCT OrderDate FROM (SELECT TOP 10 SalesOrderID FROM [Sales].[SalesOrderDetail] WHERE ProductID = 716 ORDER BY ModifiedDate DESC) AS Last10SalesOrders JOIN [Sales].[SalesOrderHeader] AS SalesOrderHeader ON Last10SalesOrders.SalesOrderID = SalesOrderHeader.SalesOrderID ORDER BY OrderDate
清单8:加入一个派生表与一个真实的表
在清单8中我建立的子查询/派生表我在清单7中,加入SalesOrderHeader表。 这样我能够肯定OrderDate大相径庭的最后一人命令ProductID = 716的10倍。
另外一个地方,您能够编写一个查询,它返回多个值的列是当你的子查询生成一个记录集,使用的关键字。 清单9中的代码演示了如何经过使用子查询的关键字值。
SELECT * FROM [Sales].[SalesOrderDetail] WHERE ProductID IN (SELECT ProductID FROM [Production].[Product] WHERE Name like '%XL%');
清单9:传递值的关键字使用子查询
清单9中的代码使用子查询返回不一样的值ProductID从Production.Product包含字符表,有一个名称“XL”。 这些ProductID返回值 而后子查询中使用的关键字来限制返回的行Sales.SalesOrderDetail表。
前女朋友一个mple使用子查询在一份声明中,修改数据
目前为止我全部的示例演示如何使用子查询在一个SELECT语句的不一样部分。 子查询也可被用来在一个INSERT、UPDATE或DELETE语句。 清单10中的代码展现了如何使用子查询在一个INSERT语句。
DECLARE @SQTable TABLE ( OrderID int, OrderDate datetime, TotalDue money, MaxOrderDate datetime); -- INSERT with SubQuery INSERT INTO @SQTable SELECT SalesOrderID, OrderDate, TotalDue, (SELECT MAX(OrderDate) FROM [Sales].[SalesOrderHeader]) FROM [Sales].[SalesOrderHeader] WHERE CustomerID = 29614; -- Display Records SELECT * FROM @SQtable;
清单10:子查询在一个INSERT语句
在个人代码在清单10中,我使用子查询计算值插入到列中MaxOrderDate。 这只是一个例子,如何在INSERT语句中使用子查询。 记住子查询也可被用来在一个更新和/或DELETE语句。
若是你读过的“子查询基本面”文档由微软(http://technet.microsoft.com/en-us/library/ms189575(v = sql.105). aspx),那么您可能已经运行在这个声明中关于性能包含子查询的语句:
“在transact - sql,一般没有语句之间的性能差别,包括子查询和语义上等价版本不。”
比较查询的性能使用子查询和一个等价查询不使用子查询我重写个人子查询在清单3中使用链接操做。 清单11显示了查询重写链接查询,至关于我在清单3中。
SELECT SOD.* FROM [Sales].[SalesOrderDetail] AS SOD INNER JOIN [Production].[Product] AS P ON SOD.ProductID = P.ProductID WHERE P.Name = 'Long-Sleeve Logo Jersey, XL';
清单11:加入查询等价于清单3中的查询
比较查询的性能在清单3中使用子查询和查询在清单11中,使用加入我将使用清单12中的代码运行两个查询。
SET STATISTICS IO ON; SET STATISTICS TIME ON; -- Listing 3 query SELECT * FROM [Sales].[SalesOrderDetail] WHERE ProductID = (SELECT ProductID FROM Production.Product WHERE Name = 'Long-Sleeve Logo Jersey, XL'); -- Listing 11 query SELECT SOD.* FROM [Sales].[SalesOrderDetail] AS SOD INNER JOIN [Production].[Product] AS P ON SOD.ProductID = P.ProductID WHERE P.Name = 'Long-Sleeve Logo Jersey, XL';
清单12:代码清单3和清单4的测试性能
清单12中的代码运行后我检查生成的消息”设置统计”语句。 经过回顾统计我发现有3309个逻辑读与查询SalesOrderDetail表,和2逻辑读产品表,每一个31女士的CPU使用。 另外我回顾了执行计划,SQL Server建立这两个查询。 我发现SQL Server产生相同的执行计划。 所以使用子查询或加入查询个人处境产生等效性能,一样记录了微软。
子查询是一个SELECT语句嵌入式数据库引擎执行与另外一个sql语句。 外查询的子查询能够独立运行,所以有时被称为一个独立的查询。 记住,任什么时候候你有一个查询的一个表达式,或是使用比较运算符,它能够只返回单个列和价值。 一般子查询可使用加入重写逻辑。 子查询是一个强大的工具来帮助你创建你的数据库引擎执行更复杂的sql语句来知足您的业务需求。
在本节中,您能够检查你理解如何使用子查询概念,回答下列问题。
完成这个句子“子查询是一个数据库引擎执行SELECT语句在另外一个sql语句,_____________________。
何时子查询只须要返回一个列和值(选择全部适用)?
transact - sql语句的WHERE子句中使用子查询老是比等效的查询执行速度较慢,不包含子查询(真或假)?
正确答案是c。外查询的子查询能够独立运行,它将返回结果。 它不须要任何列从外部查询,若是有列外查询称为相关子查询。
正确答案是c和d。子查询时须要返回一列值用做表达式,或者比较操做。 子查询时使用的关键字能够返回一个或多个值的列。 若是子查询在FROM子句中使用它能够返回一个列和一个值,但它也能够返回多个列和价值观。
正确的答案是错误的。 SQL Server优化器很聪明和极可能计算相同的两个等价的查询执行计划。 若是一个查询的执行计划,其中包含子查询和一个等价的无子查询都获得相同的执行计划而后查询都有相同的性能。