Основы вложенных запросов

Вложенным запросом называется запрос, помещаемый в инструкцию SELECT, INSERT, UPDATE или DELETE или в другой вложенный запрос. Подзапрос может быть использован везде, где разрешены выражения. В данном примере вложенный запрос используется в качестве выражения для столбца с именем MaxUnitPrice в инструкции SELECT.

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

Вложенный запрос по-другому называют внутренним запросом или внутренней операцией выбора, в то время как инструкцию, содержащую вложенный запрос, называют внешним запросом или внешней операцией выбора.

Многие инструкции языка Transact-SQL, включающие подзапросы, можно записать в виде соединений. Другие запросы могут быть осуществлены только с помощью подзапросов. В языке Transact-SQL обычно не бывает разницы в производительности между инструкцией, включающей вложенный запрос, и семантически эквивалентной версией без вложенного запроса. Однако в некоторых случаях, когда проверяется существование, соединения показывают лучшую производительность. В противном случае для устранения дубликатов вложенный запрос должен обрабатываться для получения каждого результата внешнего запроса. В таких случаях метод работы соединений дает лучшие результаты. Следующий пример содержит запросы SELECT с вложенным запросом и с соединением, возвращающие одинаковый результирующий набор:

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

/* SELECT statement built using a join that returns
   the same result set. */
SELECT Prd1. Name
FROM AdventureWorks2008R2.Production.Product AS Prd1
     JOIN AdventureWorks2008R2.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 и может включать предложение ORDER BY только вместе с предложением TOP.

Вложенный запрос может быть вложен в предложение WHERE или HAVING внешней инструкции SELECT, INSERT, UPDATE или DELETE или в другой вложенный запрос. Возможно создавать вложенность до 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.