Подзапросы: вложенные запросы в WHERE, FROM, SELECT

Что такое подзапросы и зачем они нужны? 🔎

Подзапросы (или вложенные запросы) — это SQL-запросы внутри других запросов. Они позволяют выполнять сложные выборки данных, используя результаты одного запроса в другом.

Представьте себе матрешку 🪆 — подзапросы работают по такому же принципу! Их можно использовать в:

  • Условиях WHERE для фильтрации данных
  • Части FROM для создания временных таблиц
  • Части SELECT для вычисления значений

Подзапросы делают ваш код мощнее, гибче и читабельнее. Давайте разберем каждый вариант на практике!


Подзапросы в WHERE: фильтрация по результату другого запроса 🎯

Самый распространенный случай — использование подзапроса в условии WHERE. Это позволяет фильтровать данные на основе другого запроса.

-- Найдем сотрудников, чья зарплата выше средней
SELECT employee_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

Как это работает:

  1. Внутренний запрос (SELECT AVG(salary) FROM employees) вычисляет среднюю зарплату
  2. Внешний запрос выбирает только тех сотрудников, чья зарплата больше этого значения

Важно: При использовании с операторами сравнения (>, <, =) подзапрос должен возвращать ОДНО значение.


Подзапросы в FROM: работа с временными таблицами 📊

Когда подзапрос находится в части FROM, он создает временную таблицу, с которой можно работать как с обычной.

-- Найдем отделы с количеством сотрудников больше 5
SELECT d.department_name, emp_count.count
FROM departments d
JOIN (
    SELECT department_id, COUNT(*) as count
    FROM employees
    GROUP BY department_id
) emp_count ON d.department_id = emp_count.department_id
WHERE emp_count.count > 5;

Разберем по шагам:

  1. Внутренний запрос создает временную таблицу emp_count с количеством сотрудников по отделам
  2. Основной запрос соединяет эту таблицу с таблицей отделов
  3. Фильтрует только те отделы, где сотрудников больше 5

Совет: Всегда используйте алиасы для подзапросов в FROM!


Подзапросы в SELECT: вычисления на лету 🧮

Подзапросы в SELECT позволяют добавлять вычисляемые столбцы на основе других данных.

-- Для каждого сотрудника выведем его зарплату и разницу со средней
SELECT 
    employee_name,
    salary,
    salary - (SELECT AVG(salary) FROM employees) AS diff_from_avg
FROM employees;

Особенности:

  • Подзапрос должен возвращать ровно одно значение
  • Может использоваться в выражениях (как в примере выше)
  • Полезен для сравнительного анализа

Коррелированные подзапросы: связь с внешним запросом 🔗

Особый вид подзапросов — коррелированные, где внутренний запрос ссылается на данные внешнего.

-- Найдем сотрудников с зарплатой выше средней в их отделе
SELECT e1.employee_name, e1.salary, e1.department_id
FROM employees e1
WHERE e1.salary > (
    SELECT AVG(e2.salary)
    FROM employees e2
    WHERE e2.department_id = e1.department_id
);

Что происходит:

  1. Для каждой строки внешнего запроса подзапрос вычисляет среднюю зарплату ТОЛЬКО в текущем отделе
  2. Сравнивает зарплату сотрудника с этим значением

Важно: Такие запросы могут быть медленными на больших таблицах!


EXISTS и NOT EXISTS: проверка на существование 🔍

Эти операторы работают с подзапросами и проверяют, возвращает ли подзапрос хотя бы одну строку.

-- Найдем клиентов, которые делали заказы в этом году
SELECT customer_name
FROM customers c
WHERE EXISTS (
    SELECT 1
    FROM orders o
    WHERE o.customer_id = c.customer_id
    AND YEAR(order_date) = YEAR(CURRENT_DATE)
);

Почему SELECT 1?
Для EXISTS важно только наличие строк, поэтому выбираем константу для оптимизации.


Лучшие практики работы с подзапросами 🏆

  1. Оптимизация: Подзапросы в WHERE могут быть медленными — иногда лучше использовать JOIN
  2. Читаемость: Сложные подзапросы лучше выносить в CTE (WITH-запросы)
  3. Тестирование: Всегда проверяйте подзапрос отдельно перед вставкой
  4. Индексы: Убедитесь, что поля для соединения проиндексированы
-- Пример оптимизации через JOIN вместо подзапроса
SELECT e.employee_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.location = 'New York';

Подведем итоги 🎓

  • WHERE: Фильтрация по результату подзапроса (часто с операторами сравнения)
  • FROM: Создание временных таблиц для последующих соединений
  • SELECT: Добавление вычисляемых столбцов на основе других данных
  • EXISTS/NOT EXISTS: Проверка на существование записей
  • Коррелированные подзапросы: Связь с внешним запросом для контекстной выборки

Теперь вы готовы создавать сложные запросы любой глубины! Пробуйте разные подходы и выбирайте оптимальный для каждой задачи.

Скрыть рекламу навсегда

📘 VK Видео — обучение без ограничений

Все уроки доступны без VPN, без блокировок и зависаний.

Можно смотреть с телефона, планшета или компьютера — в любое время.

▶️ Смотреть на VK Видео