JavaRush /Курсы /SQL SELF /Использование подзапросов в FROM

Использование подзапросов в FROM

SQL SELF
14 уровень , 1 лекция
Открыта

Давайте еще сильнее углубимся в кроличью нору: рассмотрим, как использовать подзапросы в конструкции FROM. Это один из самых частых подходов разработчиков SQL, поскольку позволяет создавать мощные временные таблицы прямо "на месте" и переиспользовать их, как будто они существуют в базе данных.

Представьте, что вы собираете отчёт, который требует расчётов, группировок или фильтрации данных, но при этом вы не хотите создавать дополнительные временные таблицы на сервере. Что делать? Вот тут и приходят на помощь подзапросы в FROM. Они позволяют:

  • Временно объединять данные или агрегировать их перед основным запросом.
  • Создавать структурированные наборы данных "на лету".
  • Сократить количество операций, требуя от базы данных минимального сохранения промежуточных данных.

Подзапросы в FROM действуют как мини-таблицы, которые вы можете использовать в основном запросе. Это похоже на сборку модульной конструкции: быстро, гибко и без лишних накладных расходов :)

Основы подзапросов в FROM

В подзапросах в FROM мы используем подзапросы, чтобы создать временную таблицу (или подтаблицу), которая становится частью общего запроса. Для этого нужно выполнить три ключевых шага:

  1. Написать подзапрос в конструкцию FROM в круглых скобках.
  2. Назначить алиас (псевдоним) для подзапроса.
  3. Использовать этот псевдоним, как если бы это была полноценная таблица.

Синтаксис

SELECT колонки
FROM (
    SELECT колонки
    FROM таблица
    WHERE условие
) AS псевдоним
WHERE внешнее_условие;

Звучит страшновато? Давайте перейдём к примерам.

Пример: Студенты и средний балл

Предположим, у нас есть две таблицы:

students (данные о студентах — их имя и ID):

student_id student_name
1 Alex
2 Anna
3 Dan

grades (данные об оценках студентов):

grade_id student_id grade
1 1 80
2 1 85
3 2 90
4 3 70
5 3 75

Теперь задача: получить список студентов и их средний балл.

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

SELECT s.student_name, g.avg_grade
FROM (
    SELECT student_id, AVG(grade) AS avg_grade
    FROM grades
    GROUP BY student_id
) AS g
JOIN students AS s ON s.student_id = g.student_id;

Результат:

student_name avg_grade
Alex 82.5
Anna 90.0
Dan 72.5

Временные таблицы "на лету"

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

SELECT g.student_id, g.avg_grade, g.max_grade
FROM (
    SELECT student_id, 
           AVG(grade) AS avg_grade, 
           MAX(grade) AS max_grade
    FROM grades
    GROUP BY student_id
) AS g;

Результат:

student_id avg_grade max_grade
1 82.5 85
2 90 90
3 72.5 75

Обратите внимание, что это работает, как полноценная временная таблица со своими аналогами столбцов: avg_grade и max_grade.

Когда подзапросы в FROM лучше всего использовать?

Для агрегированных данных. Если вы хотите сначала выполнить подсчёты (например, посчитать среднее, суммы или максимумы), а затем объединить результаты с другими таблицами.

Для фильтрации данных. Когда нужно отфильтровать данные до объединения с основной таблицей.

Для упрощения сложных запросов. Разделение сложных задач на этапы помогает избежать путаницы.

Пример: Отчёт о студентах с двумя уровнями обработки

Давайте представим, что мы хотим найти студентов, у которых средний балл выше 80. Мы начнём с подзапроса, который считает средние баллы, и затем используем его в фильтре.

SELECT s.student_name, g.avg_grade
FROM students AS s
JOIN (
    SELECT student_id, AVG(grade) AS avg_grade
    FROM grades
    GROUP BY student_id
) AS g ON s.student_id = g.student_id
WHERE g.avg_grade > 80;

Результат:

student_name avg_grade
Alex 82.5
Anna 90.0

Особенности использования и рекомендации

Обязательный псевдоним. Всегда присваивайте алиас подзапросу (например, AS g), иначе PostgreSQL не поймёт, как обращаться к этой "временной таблице".

Оптимизация. Подзапросы в FROM могут быть медленнее объединений таблиц (JOIN), особенно если вы фильтруете данные внутри подзапроса.

Индексация. Убедитесь, что поля, используемые для объединения, индексы и фильтры оптимизированы — это сильно влияет на производительность.

Пример сложного запроса: курсы и количество студентов

Теперь давайте сделаем реальную задачу посложнее. Представьте, что у нас есть такая таблица:

courses (список курсов):

course_id course_name
1 SQL Basics
2 Python Basics

И enrollments (записи студентов на курсы):

student_id course_id
1 1
1 2
2 1

Теперь мы хотим узнать, сколько студентов записано на каждый курс.

SELECT c.course_name, e.students_count
FROM courses AS c
JOIN (
    SELECT course_id, COUNT(student_id) AS students_count
    FROM enrollments
    GROUP BY course_id
) AS e ON c.course_id = e.course_id;

Результат:

course_name students_count
SQL Basics 2
Python Basics 1

Надеюсь лекция вам понравилась... но следующая будет еще интереснее :)

2
Задача
SQL SELF, 14 уровень, 1 лекция
Недоступна
Подсчет числа студентов с оценками
Подсчет числа студентов с оценками
2
Задача
SQL SELF, 14 уровень, 1 лекция
Недоступна
Количество студентов на каждом курсе
Количество студентов на каждом курсе
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Сергей Третяк Уровень 14
3 ноября 2025
чет я уже подзапутался зачем плодить сущности? зачем нужны разные решения одних и тех же задач? запоминать это все не лучше ли пользовать самый оптимальный? что бы потом не пришлось эту всю кашу после других разбирать.