JavaRush /Курсы /SQL SELF /Множественные JOIN в одном запросе

Множественные JOIN в одном запросе

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

Представьте, что каждая таблица в вашей базе — это часть одного большого пазла. Таблица студентов знает, кто учится, таблица курсов — чему учат, а таблица записей — кто на что записан. Но по отдельности эти кусочки ничего не скажут. Хотите увидеть картину целиком? Придётся их соединить — и вот тут на сцену выходит множественный JOIN.

В реальной жизни данные часто организованы в связанные таблицы, чтобы обеспечить структурированность и избежать избыточности. Например, в нашей базе университетов у нас есть следующие таблицы:

  • students — данные о студентах.
  • enrollments — информация о записях студентов на курсы.
  • courses — информация о курсах.

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

Порядок выполнения JOIN

При использовании нескольких JOIN, PostgreSQL обрабатывает их слева направо. Это значит, что сначала объединяются первые две таблицы, затем результат объединяется с третьей таблицей, и так далее.

Пример:

SELECT *
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id;
  1. Сначала объединяются таблицы students и enrollments по столбцу students.id = enrollments.student_id.
  2. Результат первого объединения используется для объединения с таблицей courses по столбцу enrollments.course_id = courses.id.

Порядок выполнения особенно важен, когда в запросе участвуют большие таблицы. Неправильная структура JOIN может привести к значительному снижению производительности.

Пример: Список студентов, их курсов и преподавателей

Допустим, у нас есть следующие таблицы с данными:

Таблица students:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

Таблица courses:

id name teacher
101 Mathematics Ellen Moore
102 Physics James Okoro
103 Computer Science Nina Delgado

Таблица enrollments:

student_id course_id
1 101
1 103
2 102
3 101

Запрос:

SELECT
    students.name AS student_name,
    courses.name AS course_name,
    courses.teacher AS teacher_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id;

Результат:

student_name course_name teacher_name
Otto Song Mathematics Ellen Moore
Otto Song Computer Science Nina Delgado
Maria Chi Physics James Okoro
Alex Lin Mathematics Ellen Moore

Фильтрация в запросах с множественными JOIN

Вы можете применять условия фильтрации к запросам с JOIN, чтобы ограничить количество возвращаемых данных и ускорить выполнение запроса. Например, если нужно вывести только тех студентов, которые учатся на курсе "Mathematics":

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
WHERE courses.name = 'Mathematics';

Результат:

student_name course_name
Otto Song Mathematics
Alex Lin Mathematics

Оптимизация запросов с множественными JOIN

Для работы с большими таблицами оптимизация запросов становится крайне важной. Вот несколько советов:

  1. Используйте индексы

Индексы позволяют PostgreSQL работать быстрее, особенно при объединении по ключевым полям. Убедитесь, что на столбцах student_id и course_id в таблице enrollments есть индексы.

Пример создания индекса:

CREATE INDEX idx_enrollments_student_id ON enrollments(student_id);
CREATE INDEX idx_enrollments_course_id ON enrollments(course_id);

Подробнее об индексах вы узнаете в следующих уровнях, но все же решил о них тут упомянуть. Они очень часто связаны с JOIN.

  1. Фильтруйте данные на ранних этапах

Используйте условия WHERE, чтобы уменьшить количество обрабатываемых строк до выполнения JOIN. Например:

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
WHERE 
    courses.teacher = 'Иван Петров';
  1. Минимизируйте количество строк для объединения

Вместо объединения всех записей из двух таблиц, попробуйте сначала отфильтровать их подзапросами:

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM 
    (SELECT * FROM students WHERE id IN (1, 2)) sub_students
INNER JOIN enrollments ON sub_students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;

Подробнее о вложенных SELECT вы узнаете буквально в следующем уровне :P

Пример сложного объединения: студенты, курсы и факультеты

Допустим, у нас добавляется ещё одна таблица faculties:

Таблица faculties:

id name
10 Engineering
20 Natural Sciences

Таблица courses обновляется:

id name teacher faculty_id
101 Mathematics Ellen Moore 10
102 Physics James Okoro 20
103 Computer Science Nina Delgado 10

Чтобы получить список студентов, курсов и факультетов, мы добавляем ещё один JOIN:

SELECT
    students.name AS student_name,
    courses.name AS course_name,
    faculties.name AS faculty_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
    INNER JOIN faculties ON courses.faculty_id = faculties.id;

Результат:

student_name course_name faculty_name
Otto Song Mathematics Engineering
Otto Song Computer Science Engineering
Maria Chi Physics Natural Sciences
Alex Lin Mathematics Engineering

SQL-запросы с множественными JOIN могут быть сложными, но они позволяют создавать мощные отчёты и получать ценную информацию. Если правильно их оптимизировать и структурировать, они станут вашим инструментом для работы с большими базами данных.

2
Задача
SQL SELF, 12 уровень, 1 лекция
Недоступна
Базовый запрос с множественным JOIN
Базовый запрос с множественным JOIN
2
Задача
SQL SELF, 12 уровень, 1 лекция
Недоступна
Фильтрация данных с использованием WHERE и множественных JOIN
Фильтрация данных с использованием WHERE и множественных JOIN
Комментарии (4)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Jlamma Уровень 16
19 сентября 2025
Корректную постановку задачи можно? "Напишите SQL-запрос, который выведЕт имена студентов и названия их курсов, но только для тех курсов, на которых обучается "Иван Иванов"" в момем понимании нужно выяснить на каких курсах обучается Иван Иванов и вывести сводку именно по этим курсам. Т.е. сами студенты разные, включая Ивана Иванова.
Anonymous #3590872 Уровень 14
14 июня 2025
"""Используйте условия WHERE, чтобы уменьшить количество обрабатываемых строк до выполнения JOIN. """ так SQL же отрабатывает в порядке FROM → JOIN → WHERE, как добавление WHERE поможет в данной теме в оптимизации джоин запроса
25 июня 2025
Если через команду explain посмотреть план выполнения запроса, то будет видно, что перед выполнением join планировщик выполнит отбор условия where, тем самым сократив количество объединяющих строк

Hash Join  (cost=62.76..97.85 rows=287 width=64)
  Hash Cond: (students.id = enrollments.student_id)
  ->  Seq Scan on students  (cost=0.00..22.70 rows=1270 width=36)
  ->  Hash  (cost=62.20..62.20 rows=45 width=36)
        ->  Hash Join  (cost=20.68..62.20 rows=45 width=36)
              Hash Cond: (enrollments.course_id = courses.id)
              ->  Seq Scan on enrollments  (cost=0.00..32.60 rows=2260 width=8)
              ->  Hash  (cost=20.63..20.63 rows=4 width=36)
                    ->  Seq Scan on courses  (cost=0.00..20.63 rows=4 width=36)
                          Filter: (teacher = 'James Okoro'::text)
Как видно из плана запроса, сначала выполняется фильтрация по условию where teacher = 'James Okoro', а уже потом join
Евгений Уровень 49 Expert
28 июля 2025
Ну согласно данной информации https://stackoverflow.com/questions/2509987/which-sql-query-is-faster-filter-on-join-criteria-or-where-clause в случае inner join разница в производительности для постгреса вообще отсутствует, если сравнивать ограничение в where или в inner join.