В этом руководстве вы узнаете о подзапросах SQL Server и о том, как использовать подзапросы для запроса данных.
- Введение в подзапрос SQL Server
- Вложенный подзапрос
- Типы подзапросов SQL Server
- Подзапрос SQL Server используется вместо выражения
- Подзапрос SQL Server используется с оператором IN
- Подзапрос SQL Server используется с оператором ANY
- Подзапрос SQL Server используется с оператором ALL
- Подзапрос SQL Server используется с EXISTS или NOT EXISTS
- Подзапрос SQL Server в предложении FROM
Введение в подзапрос SQL Server
Подзапрос — это запрос, вложенный в другой оператор, такой как SELECT, INSERT, UPDATE или DELETE.
Давайте рассмотрим следующий пример.
Рассмотрим таблицы заказов и клиентов из примера базы данных.

Следующий оператор показывает, как использовать подзапрос в предложении WHERE оператора SELECT для поиска заказов клиентов, находящихся в Нью-Йорке:
SELECT
order_id,
order_date,
customer_id
FROM
sales.orders
WHERE
customer_id IN(
SELECT
customer_id
FROM
sales.customers
WHERE
city = 'New York'
)
ORDER BY
order_date DESC;
Вот результат:

В этом примере следующий оператор является подзапросом:
SELECT
customer_id
FROM
sales.customers
WHERE
city = 'New York'
Обратите внимание, что вы всегда должны заключать запрос SELECT подзапроса в скобки().
Подзапрос также известен как внутренний запрос или внутренний выбор, в то время как оператор, содержащий подзапрос, называется внешним выбором или внешним запросом:

SQL Server выполняет весь приведенный выше пример запроса следующим образом:
Сначала он выполняет подзапрос, чтобы получить список идентификационных номеров клиентов, находящихся в Нью-Йорке.
SELECT
customer_id
FROM
sales.customers
WHERE
city = 'New York'

Во-вторых, SQL Server подставляет идентификационные номера клиентов, возвращаемые подзапросом в операторе IN, и выполняет внешний запрос для получения окончательного набора результатов.
Как видите, используя подзапрос, вы можете объединить два шага. Подзапрос устраняет необходимость выбора идентификационных номеров клиентов и их вставки во внешний запрос. Более того, сам запрос автоматически корректируется при изменении данных клиентов.
Вложенный подзапрос
Подзапрос может быть вложен в другой подзапрос. SQL Server поддерживает до 32 уровней вложенности. Рассмотрим следующий пример:
SELECT
product_name,
list_price
FROM
production.products
WHERE
list_price >(
SELECT
AVG(list_price)
FROM
production.products
WHERE
brand_id IN(
SELECT
brand_id
FROM
production.brands
WHERE
brand_name = 'Strider'
OR brand_name = 'Trek'
)
)
ORDER BY
list_price;

Сначала SQL Server выполняет следующий подзапрос, чтобы получить список идентификационных номеров брендов Strider и Trek:
SELECT
brand_id
FROM
production.brands
WHERE
brand_name = 'Strider'
OR brand_name = 'Trek';

Во-вторых, SQL Server вычисляет среднюю цену всех продуктов, принадлежащих этим брендам.
SELECT
AVG(list_price)
FROM
production.products
WHERE
brand_id IN(6,9)
В-третьих, SQL Server находит продукты, цена которых превышает среднюю цену всех продуктов под брендом Strider или Trek.
Типы подзапросов SQL Server
Подзапрос можно использовать во многих местах:
- Вместо выражения
- С ВНУТРЕННИМ или НЕ ВНУТРЕННИМ
- С ЛЮБЫМ или ВСЕМИ
- С СУЩЕСТВУЕТ или НЕ СУЩЕСТВУЕТ
- В операторе UPDATE, DELETE или INSERT
- В предложении FROM
Подзапрос SQL Server используется вместо выражения
Если подзапрос возвращает одно значение, его можно использовать везде, где используется выражение.
В следующем примере подзапрос используется как выражение столбца с именем max_list_price в операторе SELECT.
SELECT
order_id,
order_date,
(
SELECT
MAX(list_price)
FROM
sales.order_items i
WHERE
i.order_id = o.order_id
) AS max_list_price
FROM
sales.orders o
order by order_date desc;

Подзапрос SQL Server используется с оператором IN
Подзапрос, используемый с оператором IN, возвращает набор из нуля или более значений. После того, как подзапрос возвращает значения, внешний запрос использует их.
Следующий запрос находит названия всех горных и шоссейных велосипедов, которые продаются в веломагазинах.
SELECT
product_id,
product_name
FROM
production.products
WHERE
category_id IN(
SELECT
category_id
FROM
production.categories
WHERE
category_name = 'Mountain Bikes'
OR category_name = 'Road Bikes'
);

Этот запрос оценивается в два этапа:
- Во-первых, внутренний запрос возвращает список идентификационных номеров категорий, которые соответствуют названию «Горные велосипеды» и коду «Шоссейные велосипеды».
- Во-вторых, эти значения подставляются во внешний запрос, который находит названия продуктов, идентификационный номер категории которых совпадает с одним из значений в списке.
Подзапрос SQL Server используется с оператором ANY
Подзапрос вводится с помощью оператора ANY и имеет следующий синтаксис:
scalar_expression comparison_operator ANY(subquery)
Предполагая, что подзапрос возвращает список значений v1, v2, … vn. Оператор ANY возвращает TRUE, если одно из значений пары сравнения(scalar_expression, vi) оценивается как TRUE; в противном случае он возвращает FALSE.
Например, следующий запрос находит продукты, цены на которые больше или равны средней цене на продукты любого бренда.
SELECT
product_name,
list_price
FROM
production.products
WHERE
list_price >= ANY(
SELECT
AVG(list_price)
FROM
production.products
GROUP BY
brand_id
)

Для каждого бренда подзапрос находит максимальную цену по прейскуранту. Внешний запрос использует эти максимальные цены и определяет, какая цена по прейскуранту отдельного продукта больше или равна максимальной цене по прейскуранту любого бренда.
Подзапрос SQL Server используется с оператором ALL
Оператор ALL имеет тот же синтаксис, что и оператор ANY :
scalar_expression comparison_operator ALL(subquery)
Оператор ALL возвращает значение TRUE, если все пары сравнения(scalar_expression, vi) дают значение TRUE; в противном случае он возвращает значение FALSE.
Следующий запрос находит продукты, цена по прейскуранту которых больше или равна средней цене по прейскуранту, возвращаемой подзапросом:
SELECT
product_name,
list_price
FROM
production.products
WHERE
list_price >= ALL(
SELECT
AVG(list_price)
FROM
production.products
GROUP BY
brand_id
)

Подзапрос SQL Server используется с EXISTS или NOT EXISTS
Ниже показан синтаксис подзапроса, введенного с помощью оператора EXISTS :
WHERE [NOT] EXISTS(subquery)
Оператор EXISTS возвращает TRUE, если подзапрос возвращает результаты; в противном случае он возвращает FALSE.
Оператор NOT EXISTS отрицает оператор EXISTS.
Следующий запрос находит клиентов, купивших продукцию в 2017 году:
SELECT
customer_id,
first_name,
last_name,
city
FROM
sales.customers c
WHERE
EXISTS(
SELECT
customer_id
FROM
sales.orders o
WHERE
o.customer_id = c.customer_id
AND YEAR(order_date) = 2017
)
ORDER BY
first_name,
last_name;

Если вы используете NOT EXISTS вместо EXISTS, вы можете найти клиентов, которые не купили никаких продуктов в 2017 году.
SELECT
customer_id,
first_name,
last_name,
city
FROM
sales.customers c
WHERE
NOT EXISTS(
SELECT
customer_id
FROM
sales.orders o
WHERE
o.customer_id = c.customer_id
AND YEAR(order_date) = 2017
)
ORDER BY
first_name,
last_name;

Подзапрос SQL Server в предложении FROM
Предположим, что вы хотите найти среднее значение суммы заказов всех продавцов. Для этого вы можете сначала найти количество заказов по персоналу:
SELECT staff_id, COUNT(order_id) order_count FROM sales.orders GROUP BY staff_id;

Затем вы можете применить функцию AVG() к этому набору результатов. Поскольку запрос возвращает набор результатов, который выглядит как виртуальная таблица, вы можете поместить весь запрос в предложение FROM другого запроса следующим образом:
SELECT
AVG(order_count) average_order_count_by_staff
FROM
(
SELECT
staff_id,
COUNT(order_id) order_count
FROM
sales.orders
GROUP BY
staff_id
) t;
![]()
Запрос, который вы помещаете в предложение FROM, должен иметь псевдоним таблицы. В этом примере мы использовали t в качестве псевдонима таблицы для подзапроса. Чтобы получить окончательный результат, SQL Server выполняет следующие шаги:
- Выполните подзапрос в предложении FROM.
- Используйте результат подзапроса и выполните внешний запрос.
В этом руководстве вы узнали о концепции подзапросов SQL Server и о том, как использовать различные типы подзапросов для запроса данных.




