JavaRush /Курсы /SQL SELF /Типичные ошибки при использовании JOIN

Типичные ошибки при использовании JOIN

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

Теперь настало время поговорить о жизни. О той её стороне, которой не избежать: ошибки. Ловить, исправлять и понимать ошибки — это обязательная часть работы с данными. Давайте разберём, какие грабли происходят при работе с JOIN в SQL, и как их обойти.

Ошибка 1: Пропуск условия соединения — создание декартового произведения

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

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

Студенты (students):

student_id name
1 Otto
2 Anna

Курсы (courses):

course_id course_name
101 Математика
102 История

Теперь напишем запрос, забыв про ON:

SELECT *
FROM students
JOIN courses;

Результат:

student_id name course_id course_name
1 Otto 101 Математика
1 Otto 102 История
2 Anna 101 Математика
2 Anna 102 История

Не похоже на правду, верно? Этот кошмар называется декартовым произведением.

Как исправить: используйте ON, чтобы указать, как связаны данные в таблицах.

SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;

И тут возникает новая глава ошибки...

Защита от дурака

Это настолько распространенная проблема, что в PostgreSQL запретили использование JOIN без указания ON и условия.

Если вам нужно объединить каждую строку с каждой, то можно использовать синтаксис без JOIN:

SELECT *
FROM students, courses;

Еще вариант 3 вариант - когда JOIN без ON работает:

  • С NATURAL JOIN — автоматически подбирает одинаковые по названию колонки.
  • С USING — указываете список колонок по которым объединяются колонки.
  • CROSS JOIN — всегда без условия - то же, что и декартово произведение.

Ошибка 2: Неверное условие соединения

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

Допустим, мы хотим получить список студентов и курсов, на которые они записаны, но ошибаемся и соединяем таблицы по несвязанным полям:

SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;

Такой запрос приведёт к некорректному результату, так как student_id и course_id — это совершенно разные вещи.

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

SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;

Ошибка 3: Дублирование строк в результате

Когда вы добавляете несколько JOIN в запрос, иногда это приводит к дублированию строк. Это происходит, если в таблицах JOIN есть повторяющиеся записи, или вы неверно указали условия объединения.

Допустим, студент Otto записан дважды на один и тот же курс в таблице enrollments.

Записи в enrollments:

student_id course_id
1 101
1 101

Теперь запрос с JOIN даст такие результаты:

SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;

Результат:

name course_name
Otto Математика
Otto Математика

Как исправить: во-первых, убедитесь, что в ваших таблицах нет дублирующихся данных. Во-вторых, если это ожидаемое поведение, удаляйте дубликаты с помощью DISTINCT:

SELECT DISTINCT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;

Ошибка 4: Потеря строк при использовании INNER JOIN

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

Допустим, у нас есть студент, который ещё не записан ни на один курс:

Студенты (students):

student_id name
1 Otto
2 Anna
3 Dhany

Записи (enrollments):

student_id course_id
1 101
2 102

Теперь запрос с INNER JOIN:

SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;

Результат:

name course_name
Otto Математика
Anna История

А где Dhany? Если вы хотите включить студентов без курсов, нужно использовать LEFT JOIN:

SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id;

Ошибка 5: Неправильная обработка NULL значений

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

Пример: вы используете LEFT JOIN, но затем добавляете WHERE для фильтрации.

SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id
WHERE courses.course_name = 'Математика';

Теперь студенты без курсов не будут включены в результат, даже если вы использовали LEFT JOIN.

Как исправить: если хотите включить строки с отсутствующими курсами, замените WHERE на ON или добавьте дополнительное условие:

SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id
WHERE courses.course_name IS NULL OR courses.course_name = 'Математика';

Ошибка 6: Путаница между типами соединений

Вы путаетесь, какой тип соединения использовать. Например, применяете RIGHT JOIN, тогда как можно было бы воспользоваться LEFT JOIN, просто поменяв порядок таблиц.

Как избежать путаницы:

  • Используйте LEFT JOIN, если можете. Это более интуитивно понятно.
  • Измените порядок таблиц, чтобы избавиться от необходимости в RIGHT JOIN.
2
Задача
SQL SELF, 12 уровень, 4 лекция
Недоступна
Исправление декартового произведения
Исправление декартового произведения
2
Задача
SQL SELF, 12 уровень, 4 лекция
Недоступна
Избежание потери данных с помощью `LEFT JOIN`
Избежание потери данных с помощью `LEFT JOIN`
1
Опрос
Множественные JOIN, 12 уровень, 4 лекция
Недоступен
Множественные JOIN
Множественные JOIN
Комментарии (10)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Dmitry Ivanchenko Уровень 15
14 января 2026
Решение второй задачи это копи паст решения первой задачи с заменой INNER на LEFT. Просто дно
Сергій Бабич Уровень 33
16 декабря 2025
В завданні вказано: Если у студента нет записей в таблице `enrollments`, в столбце `course_name` должно отображаться значение `NULL`. Я так розумію, що мається на увазі саме запис `NULL` в пустому полі, а приймає відповідь навпаки з пустим полем: Иван Математика Ольга История Дмитрий Або тоді треба коректно вказувати завдання. Раніше була задача з схожим моментом і там якраз треба був запис, а не пусте поле.
Anemon Уровень 13 Expert
15 сентября 2025
Тесты опять кривые :С
25 июня 2025
Теперь напишем запрос, забыв про ON:

SELECT *
FROM students
JOIN courses;
В PostgreSQL выполнить так JOIN не возможно, обязательно необходимо условие ON. Использование JOIN без ON присуще СУБД MySQL. Так же в курсе на 10 уровне, 2 лекция, идет описание функций GREATEST() и LEAST() и описывается, что при хотя бы одном значении NULL весь результат будет NULL, такое поведение присуще MySQL. В PostgreSQL эти функции работают иначе, они вернут NULL, если только все значения будет иметь NULL. Выходит курс по PostgreSQL взят из курса по MySQL без учета различий этих СУБД.
Юрий Уровень 60
27 июня 2025
Да, подтверждаю без ON нельзя но можно через запятую, не указывая условий.

select * from products p, products p2;
Но так делать не стоит - так как в сложных много join запросах с большим количеством условий вы это потеряете И если вам действительно нужно декартово произведение - используйте cross join он нагляден и будет виден сразу.

select * from products p
 cross join    products p2;
Anemon Уровень 13 Expert
15 сентября 2025
В лекции написано, что так нельзя делать, наверное вы не дочитали. Подозреваю что эта информация была нужна для ознакомления, потому как подобное соединение всё ещё возможно, но отдельной командой.
29 декабря 2025
В лекции написано, что пропуск ON приводит к декартовому произведению

Ошибка 1: Пропуск условия соединения — создание декартового произведения
Серега Батенин Уровень 12
24 июня 2025
Как можно сказать что будет, если мы не знаем условия фильтрации?? ожидают Исключение
Серега Батенин Уровень 12
24 июня 2025
Очередная угадайка. То ли left join хотят услышать, то ли full outer... если что ждут Левый
JaFFar Уровень 25
17 июля 2025
Того же мнения - что собираетесь фильтровать, о чем речь, гадать нужно? ))