Подзапросы в FROM: временные таблицы в запросе
Когда подзапросы в FROM — это сила 💪
Подзапросы в FROM — это как волшебный портал в мир SQL:
вы создаёте временную таблицу прямо внутри запроса и используете её, как обычную. Это мощный инструмент для:
- Разбивки сложных запросов на понятные шаги.
- Агрегации данных перед дальнейшим анализом.
- Создания «виртуальных» таблиц на лету.
👉 Важно: временная таблица из подзапроса существует только во время выполнения запроса!
Базовый синтаксис: просто, как дважды два
SELECT
временная_таблица.поле1,
временная_таблица.поле2
FROM (
-- Здесь ваш подзапрос, который создаёт временную таблицу
SELECT
поле1,
поле2
FROM исходная_таблица
WHERE условие
) AS временная_таблица -- Алиас обязателен!
🔹 Почему алиас? Без него SQL не поймёт, как обращаться к временной таблице.
Пример: средняя зарплата по отделам после фильтрации
Допустим, у нас есть таблица employees:
| id | name | department | salary |
|---|---|---|---|
| 1 | Иван | IT | 100000 |
| 2 | Мария | HR | 80000 |
| 3 | Алекс | IT | 110000 |
| 4 | Ольга | HR | 75000 |
Задача: найти среднюю зарплату по отделам, но только для сотрудников с зарплатой > 80 000.
Решение с подзапросом в FROM:
SELECT
dep_stats.department,
AVG(dep_stats.salary) AS avg_salary
FROM (
SELECT
department,
salary
FROM employees
WHERE salary > 80000
) AS dep_stats
GROUP BY dep_stats.department;
Результат:
| department | avg_salary |
|---|---|
| IT | 105000 |
🔍 Что произошло?
1. Подзапрос создал временную таблицу dep_stats только с сотрудниками, у которых salary > 80000.
2. Внешний запрос сгруппировал данные по отделам и посчитал среднюю зарплату.
Вложенные подзапросы: когда нужно углубиться
Можно использовать несколько уровней вложенности (но без фанатизма!):
SELECT
final_data.department,
final_data.max_salary
FROM (
SELECT
department,
MAX(salary) AS max_salary
FROM (
SELECT
department,
salary
FROM employees
WHERE name LIKE 'А%' -- Только имена на "А"
) AS filtered_employees
GROUP BY department
) AS final_data
WHERE final_data.max_salary > 90000;
📌 Совет от Данилы Бежина: Если вложенность больше 2-3 уровней, возможно, стоит вынести логику в CTE (Common Table Expressions).
Подзапросы + JOIN: комбо-удар 🥋
Временные таблицы можно джойнить с другими:
SELECT
e.name,
e.salary,
dept_stats.avg_salary
FROM employees e
JOIN (
SELECT
department,
AVG(salary) AS avg_salary
FROM employees
GROUP BY department
) AS dept_stats ON e.department = dept_stats.department;
Результат:
| name | salary | avg_salary |
|---|---|---|
| Иван | 100000 | 105000 |
| Мария | 80000 | 77500 |
| Алекс | 110000 | 105000 |
| Ольга | 75000 | 77500 |
🎯 Фишка: теперь у каждого сотрудника есть информация о средней зарплате в его отделе!
Ограничения и подводные камни
- Производительность: сложные подзапросы могут замедлить запрос.
- Читаемость: много вложенных подзапросов усложняют понимание кода.
- Алиасы: если забудете дать имя временной таблице — получите ошибку.
💡 Простое правило: если подзапрос в FROM занимает больше 10 строк — подумайте о CTE или временной таблице.
Практика: решаем реальную задачу
Задача: найти отделы, где суммарная зарплата выше средней по компании.
SELECT
department,
SUM(salary) AS total_salary
FROM employees
GROUP BY department
HAVING SUM(salary) > (
SELECT AVG(total_dept_salary)
FROM (
SELECT
department,
SUM(salary) AS total_dept_salary
FROM employees
GROUP BY department
) AS salary_stats
);
Разбор:
1. Вложенный подзапрос считает суммарные зарплаты по отделам.
2. Внешний подзапрос вычисляет среднее из этих сумм.
3. Основной запрос фильтрует отделы через HAVING.
Вуаля! Теперь вы мастер подзапросов в FROM. 🚀