В предыдущих уроках мы использовали «автономные» подзапросы, которые могли работать сами по себе. В этом уроке мы познакомимся с коррелированными подзапросами - более продвинутым типом подзапросов, который зависит от значений из внешнего запроса.
Подзапрос называется коррелированным, если он ссылается на столбец таблицы из внешнего запроса. В отличие от обычного подзапроса, коррелированный подзапрос не может быть выполнен независимо от внешнего.
Как это работает:
WHERE (или заполнения SELECT).Заметка о производительности: Поскольку коррелированный подзапрос потенциально выполняется один раз для каждой строки внешнего запроса, он может работать медленнее, чем JOIN или обычный подзапрос, на очень больших объемах данных.
Чаще всего они используются для сравнения значения строки с набором данных, относящимся именно к этой строке.
Сценарий: Найти все фильмы, стоимость замены которых выше средней стоимости замены фильмов в той же категории рейтинга (например, G, PG, R).
SELECT
title,
rating,
replacement_cost
FROM
film AS f1
WHERE
replacement_cost > (
SELECT AVG(replacement_cost)
FROM film AS f2
WHERE f1.rating = f2.rating
);
f1.rating = f2.rating связывает внутренний запрос с текущей строкой внешнего.Вы можете использовать коррелированные подзапросы для получения описательных данных или агрегатов для каждой строки без использования GROUP BY.
Сценарий: Показать список категорий и название самого длинного фильма в каждой из них.
SELECT
c.name AS category_name,
(
SELECT f.title
FROM film f
JOIN film_category fc ON f.film_id = fc.film_id
WHERE fc.category_id = c.category_id
ORDER BY f.length DESC
LIMIT 1) AS longest_film_title
FROM
category AS c;
Мы рассматривали оператор EXISTS в предыдущем уроке. EXISTS почти всегда используется именно с коррелированным подзапросом.
Сценарий: Найти клиентов, которые арендовали хотя бы один фильм в конкретном магазине (Store 1).
SELECT
first_name,
last_name
FROM
customer AS c
WHERE
EXISTS (
SELECT 1
FROM rental AS r
INNER JOIN inventory AS i ON r.inventory_id = i.inventory_id
WHERE r.customer_id = c.customer_id
AND i.store_id = 1
);