SqlServer子查询基础知识详解

子查询是一个嵌套在 SELECT、INSERT、UPDATE 或 DELETE 语句或其他子查询中的查询。任何允许使用表达式的地方都可以使用子查询。在以下示例中,子查询在 SELECT 语句中被用作名为 MaxUnitPrice 的列表达式。

SELECT Ord.SalesOrderID, Ord.OrderDate,
    (SELECT MAX(OrdDet.UnitPrice)
     FROM AdventureWorks.Sales.SalesOrderDetail AS OrdDet
     WHERE Ord.SalesOrderID = OrdDet.SalesOrderID) AS MaxUnitPrice
FROM AdventureWorks.Sales.SalesOrderHeader AS Ord

子查询也称为内部查询或内部选择,而包含子查询的语句也称为外部查询或外部选择。

许多包含子查询的 Transact-SQL 语句都可以改用联接表示。其他问题只能通过子查询提出。在 Transact-SQL 中,包含子查询的语句和语义上等效的不包含子查询的语句在性能上通常没有差别。但是,在一些必须检查存在性的情况中,使用联接会产生更好的性能。否则,为确保消除重复值,必须为外部查询的每个结果都处理嵌套查询。所以在这些情况下,联接方式会产生更好的效果。以下示例显示了返回相同结果集的 SELECT 子查询和 SELECT 联接:

/* SELECT statement built using a subquery. */
SELECT Name
FROM AdventureWorks.Production.Product
WHERE ListPrice =
    (SELECT ListPrice
     FROM AdventureWorks.Production.Product
     WHERE Name = 'Chainring Bolts' )

/* SELECT statement built using a join that returns
   the same result set. */
SELECT Prd1. Name
FROM AdventureWorks.Production.Product AS Prd1
     JOIN AdventureWorks.Production.Product AS Prd2
       ON (Prd1.ListPrice = Prd2.ListPrice)
WHERE Prd2. Name = 'Chainring Bolts'

嵌套在外部 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 2005 实际处理带有子查询的 Transact-SQL 语句的方式)。

有三种基本的子查询。它们是:

在通过 IN 或由 ANY 或 ALL 修改的比较运算符引入的列表上操作。
通过未修改的比较运算符引入且必须返回单个值。
通过 EXISTS 引入的存在测试。

子查询规则

子查询受下列限制的制约:

通过比较运算符引入的子查询选择列表只能包括一个表达式或列名称(对 SELECT * 执行的 EXISTS 或对列表执行的 IN

子查询除外)。 如果外部查询的 WHERE 子句包括列名称,它必须与子查询选择列表中的列是联接兼容的。 ntext、text 和 image 数据类型不能用在子查询的选择列表中。 由于必须返回单个值,所以由未修改的比较运算符(即后面未跟关键字 ANY 或 ALL 的运算符)引入的子查询不能包含 GROUP BY 和

HAVING 子句。 包含 GROUP BY 的子查询不能使用 DISTINCT 关键字。 不能指定 COMPUTE 和 INTO 子句。 只有指定了 TOP 时才能指定 ORDER BY。 不能更新使用子查询创建的视图。 按照惯例,由 EXISTS 引入的子查询的选择列表有一个星号 (*),而不是单个列名。因为由 EXISTS引入的子查询创建了存在测试并返回 TRUE 或 FALSE 而非数据,所以其规则与标准选择列表的规则相同。

在子查询中限定列名

在下列示例中,外部查询的 WHERE 子句中的 CustomerID 列是由外部查询的 FROM 子句中的表名 (Sales.Store) 隐性限定的。对子查询的选择列表中 CustomerID 的引用则是由子查询的 FROM 子句(即通过 Sales.Customer 表)来限定的。

USE AdventureWorks;
GO
SELECT Name
FROM Sales.Store
WHERE CustomerID NOT IN
    (SELECT CustomerID
     FROM Sales.Customer
     WHERE TerritoryID = 5)

一般的规则是,语句中的列名通过同级 FROM 子句中引用的表来隐性限定。如果子查询的 FROM 子句中引用的表中不存在列,则它是由外部查询的 FROM 子句中引用的表隐性限定的。

下例是使用这些隐性假设限定后查询的样式:

USE AdventureWorks;
GO
SELECT Name
FROM Sales.Store
WHERE Sales.Store.CustomerID NOT IN
    (SELECT Sales.Customer.CustomerID
     FROM Sales.Customer
     WHERE TerritoryID = 5)

显式表述一个表名绝对不会出错,而且用显式限定替代有关表名的隐性假定总是可能的。

注意: 如果子查询的 FROM 子句中引用的表中不存在子查询中引用的列,而外部查询的 FROM 子句引用的表中存在该列,则该查询可以正确执行。SQL Server 用外部查询中的表名隐性限定子查询中的列。

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐