子查询是一个 SELECT 查询,它返回单个值且嵌套在 SELECT、INSERT、UPDATE、DELETE 语句或其它子查询中。任何允许使用表达式的地方都可以使用子查询。下例中,一个子查询用作 SELECT 语句中名为 MaxUnitPrice 的列表达式。
SELECT Ord.OrderID, Ord.OrderDate,
(SELECT MAX(OrdDet.UnitPrice)
FROM Northwind.dbo.[Order Details] AS OrdDet
WHERE Ord.OrderID = OrdDet.OrderID) AS MaxUnitPrice
FROM Northwind.dbo.Orders AS Ord
子查询也称为内部查询或内部选择,而包含子查询的语句也称为外部查询或外部选择。
许多包含子查询的 Transact-SQL 语句都可以改为用联接表示。而其它一些问题只能由子查询提出。在 Transact-SQL 中,包括子查询的语句和不包括子查询但语义上等效的语句在性能方面通常没有区别。但是,在一些必须检查存在性的情况中,使用联接会产生更好的性能。否则,为确保消除重复值,必须为外部查询的每个结果都处理嵌套查询。所以在这些情况下,联接方式会产生更好的效果。下面的示例显示返回相同结果集的 SELECT 子查询和SELECT 联接:
/**//* SELECT statement built using a subquery. */
SELECT ProductName
FROM Northwind.dbo.Products
WHERE UnitPrice =
(SELECT UnitPrice
FROM Northwind.dbo.Products
WHERE ProductName = 'Sir Rodney''s Scones')
/**//* SELECT statement built using a join that returns
the same result set. */
SELECT Prd1.ProductName
FROM Northwind.dbo.Products AS Prd1
JOIN Northwind.dbo.Products AS Prd2
ON (Prd1.UnitPrice = Prd2.UnitPrice)
WHERE Prd2.ProductName = 'Sir Rodney''s Scones'
嵌套在外部 SELECT 语句中的子查询包括以下组件:
包含标准选择列表组件的标准 SELECT 查询。
包含一个或多个表或者视图名的标准 FROM 子句。
可选的 WHERE 子句。
可选的 GROUP BY 子句。
可选的 HAVING 子句。
子查询的 SELECT 查询总是使用圆括号括起来。且不能包括 COMPUTE 或 FOR BROWSE 子句,如果同时指定 TOP 子句,则可能只包括 ORDER BY 子句。
子查询可以嵌套在外部 SELECT、INSERT、UPDATE 或 DELETE 语句的 WHERE 或 HAVING 子句内,或者其它子查询中。尽管根据可用内存和查询中其它表达式的复杂程度不同,嵌套限制也有所不同,但嵌套到 32 层是可能的。个别查询可能会不支持 32 层嵌套。任何可以使用表达式的地方都可以使用子查询,只要它返回的是单个值。
如果某个表只出现在子查询中而不出现在外部查询中,那么该表中的列就无法包含在输出中(外部查询的选择列表)。
包括子查询的语句通常采用以下格式中的一种:
WHERE expression [NOT] IN (subquery)
WHERE expression comparison_operator [ANY | ALL] (subquery)
WHERE [NOT] EXISTS (subquery)
在某些 Transact-SQL 语句中,子查询可以像一个独立的查询一样进行评估。从概念上讲,子查询结果将代入外部查询中(尽管不必知道 Microsoft® SQL Server™ 实际上如何通过子查询处理 Transact-SQL 语句)。
有三种基本的子查询。它们是:
在通过 IN 引入的列表或者由 ANY 或 ALL 修改的比较运算符的列表上进行操作。
通过无修改的比较运算符引入,并且必须返回单个值。
通过 EXISTS 引入的存在测试。
使用 FROM 子句
在每一条要从表或视图中检索数据的 SELCET 语句中,都需要使用 FROM 子句。用 FROM 子句可以:
列出选择列表和 WHERE 子句中所引用的列所在的表和视图。可用 AS 子句为表和视图的名称指定别名。
联接类型。这些类型由 ON 子句中指定的联接条件限定。
FROM 子句是用逗号分隔的表名、视图名和 JOIN 子句的列表。
Transact-SQL 具有扩展功能,可支持在 FROM 子句中指定除表或视图之外的其它对象。这些对象返回结果集,也就是 OLE DB 术语中所说的行集,该结果集构成了虚拟表。然后 SELECT 语句就像操作表一样操作这些结果集。
FROM 子句可以指定:
一个或多个表或视图。例如: SELECT *
FROM Shippers
两个表或视图之间的联接: SELECT Cst.CustomerID, Cst.CompanyName, Cst.ContactName,
Ord.ShippedDate, Ord.Freight
FROM Northwind.dbo.Orders AS Ord
JOIN
Northwind.dbo.Customers AS Cst
ON (Cst.CustomerID = Ord.CustomerID)
一个或多个派生表,这些派生表是 FROM 子句中的 SELECT 语句,以别名或用户指定的名称来引用这些派生表。FROM 子句中 SELECT 语句的结果集构成了外层 SELECT 语句所用的表。例如,下面的 SELECT 语句使用派生表查找是否有哪家书店备有 pubs 数据库中所有种类的书籍: SELECT ST.stor_id, ST.stor_name
FROM stores AS ST,
(SELECT stor_id, COUNT(DISTINCT title_id) AS title_count
FROM sales
GROUP BY stor_id
) AS SA
WHERE ST.stor_id = SA.stor_id
AND SA.title_count = (SELECT COUNT(*) FROM titles) 注意,其中AS SA 是必须的,必须为FROM 子句中的 SELECT 语句指定别名。
用 sp_addlinkedserver 定义的链接服务器中的一个或多个表或视图。链接服务器可以是任何 OLE DB 数据源。
用 OPENROWSET 或 OPENQUERY 函数返回的 OLE DB 行集。
SELECT Ord.OrderID, Ord.OrderDate,
(SELECT MAX(OrdDet.UnitPrice)
FROM Northwind.dbo.[Order Details] AS OrdDet
WHERE Ord.OrderID = OrdDet.OrderID) AS MaxUnitPrice
FROM Northwind.dbo.Orders AS Ord
子查询也称为内部查询或内部选择,而包含子查询的语句也称为外部查询或外部选择。
许多包含子查询的 Transact-SQL 语句都可以改为用联接表示。而其它一些问题只能由子查询提出。在 Transact-SQL 中,包括子查询的语句和不包括子查询但语义上等效的语句在性能方面通常没有区别。但是,在一些必须检查存在性的情况中,使用联接会产生更好的性能。否则,为确保消除重复值,必须为外部查询的每个结果都处理嵌套查询。所以在这些情况下,联接方式会产生更好的效果。下面的示例显示返回相同结果集的 SELECT 子查询和SELECT 联接:
/**//* SELECT statement built using a subquery. */
SELECT ProductName
FROM Northwind.dbo.Products
WHERE UnitPrice =
(SELECT UnitPrice
FROM Northwind.dbo.Products
WHERE ProductName = 'Sir Rodney''s Scones')
/**//* SELECT statement built using a join that returns
the same result set. */
SELECT Prd1.ProductName
FROM Northwind.dbo.Products AS Prd1
JOIN Northwind.dbo.Products AS Prd2
ON (Prd1.UnitPrice = Prd2.UnitPrice)
WHERE Prd2.ProductName = 'Sir Rodney''s Scones'
嵌套在外部 SELECT 语句中的子查询包括以下组件:
包含标准选择列表组件的标准 SELECT 查询。
包含一个或多个表或者视图名的标准 FROM 子句。
可选的 WHERE 子句。
可选的 GROUP BY 子句。
可选的 HAVING 子句。
子查询的 SELECT 查询总是使用圆括号括起来。且不能包括 COMPUTE 或 FOR BROWSE 子句,如果同时指定 TOP 子句,则可能只包括 ORDER BY 子句。
子查询可以嵌套在外部 SELECT、INSERT、UPDATE 或 DELETE 语句的 WHERE 或 HAVING 子句内,或者其它子查询中。尽管根据可用内存和查询中其它表达式的复杂程度不同,嵌套限制也有所不同,但嵌套到 32 层是可能的。个别查询可能会不支持 32 层嵌套。任何可以使用表达式的地方都可以使用子查询,只要它返回的是单个值。
如果某个表只出现在子查询中而不出现在外部查询中,那么该表中的列就无法包含在输出中(外部查询的选择列表)。
包括子查询的语句通常采用以下格式中的一种:
WHERE expression [NOT] IN (subquery)
WHERE expression comparison_operator [ANY | ALL] (subquery)
WHERE [NOT] EXISTS (subquery)
在某些 Transact-SQL 语句中,子查询可以像一个独立的查询一样进行评估。从概念上讲,子查询结果将代入外部查询中(尽管不必知道 Microsoft® SQL Server™ 实际上如何通过子查询处理 Transact-SQL 语句)。
有三种基本的子查询。它们是:
在通过 IN 引入的列表或者由 ANY 或 ALL 修改的比较运算符的列表上进行操作。
通过无修改的比较运算符引入,并且必须返回单个值。
通过 EXISTS 引入的存在测试。
使用 FROM 子句
在每一条要从表或视图中检索数据的 SELCET 语句中,都需要使用 FROM 子句。用 FROM 子句可以:
列出选择列表和 WHERE 子句中所引用的列所在的表和视图。可用 AS 子句为表和视图的名称指定别名。
联接类型。这些类型由 ON 子句中指定的联接条件限定。
FROM 子句是用逗号分隔的表名、视图名和 JOIN 子句的列表。
Transact-SQL 具有扩展功能,可支持在 FROM 子句中指定除表或视图之外的其它对象。这些对象返回结果集,也就是 OLE DB 术语中所说的行集,该结果集构成了虚拟表。然后 SELECT 语句就像操作表一样操作这些结果集。
FROM 子句可以指定:
一个或多个表或视图。例如: SELECT *
FROM Shippers
两个表或视图之间的联接: SELECT Cst.CustomerID, Cst.CompanyName, Cst.ContactName,
Ord.ShippedDate, Ord.Freight
FROM Northwind.dbo.Orders AS Ord
JOIN
Northwind.dbo.Customers AS Cst
ON (Cst.CustomerID = Ord.CustomerID)
一个或多个派生表,这些派生表是 FROM 子句中的 SELECT 语句,以别名或用户指定的名称来引用这些派生表。FROM 子句中 SELECT 语句的结果集构成了外层 SELECT 语句所用的表。例如,下面的 SELECT 语句使用派生表查找是否有哪家书店备有 pubs 数据库中所有种类的书籍: SELECT ST.stor_id, ST.stor_name
FROM stores AS ST,
(SELECT stor_id, COUNT(DISTINCT title_id) AS title_count
FROM sales
GROUP BY stor_id
) AS SA
WHERE ST.stor_id = SA.stor_id
AND SA.title_count = (SELECT COUNT(*) FROM titles) 注意,其中AS SA 是必须的,必须为FROM 子句中的 SELECT 语句指定别名。
用 sp_addlinkedserver 定义的链接服务器中的一个或多个表或视图。链接服务器可以是任何 OLE DB 数据源。
用 OPENROWSET 或 OPENQUERY 函数返回的 OLE DB 行集。