Подзапросы: запрос внутри запроса
Подзапрос, это SELECT внутри другого SELECT. Это позволяет использовать результат одного запроса в другом.
Зачем нужны подзапросы
Иногда условие фильтрации, не фиксированное число, а результат другого запроса:
-- Пользователи старше СРЕДНЕГО возраста
-- Среднее заранее не знаем, оно в базе
SELECT name, age
FROM users
WHERE age > (SELECT AVG(age) FROM users);
Подзапрос (SELECT AVG(age) FROM users) выполняется первым, возвращает одно число, которое используется в WHERE.
Подзапрос в WHERE
-- Клиенты, сделавшие хотя бы один заказ
SELECT name, email
FROM customers
WHERE id IN (
SELECT DISTINCT customer_id
FROM orders
WHERE status = 'completed'
);
-- Клиенты без заказов
SELECT name
FROM customers
WHERE id NOT IN (
SELECT DISTINCT customer_id
FROM orders
WHERE customer_id IS NOT NULL
);
Подзапрос в FROM
Результат подзапроса можно использовать как таблицу:
SELECT city, ROUND(AVG(avg_check), 0) AS city_avg
FROM (
SELECT
c.city,
AVG(o.amount) AS avg_check
FROM orders o
JOIN customers c ON o.customer_id = c.id
GROUP BY c.id, c.city
) AS customer_stats
GROUP BY city
ORDER BY city_avg DESC;
Когда подзапросы становятся нечитаемыми
Вложенные подзапросы быстро становятся сложными:
SELECT * FROM (
SELECT * FROM (
SELECT * FROM orders WHERE ...
) t1 WHERE ...
) t2 WHERE ...
Для таких случаев существует лучший инструмент, CTE.
💡 Главная мысль: Подзапрос, запрос внутри запроса. Полезен когда условие, это результат другого запроса. Для сложной логики лучше использовать CTE.