JavaRush /Курсы /SQL SELF /Работа с NULL значениями при объединении да...

Работа с NULL значениями при объединении данных

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

Представьте, что вы объединяете две таблицы: students (студенты) и enrollments (записи на курсы). Если в таблице enrollments нет информации о каком-то студенте, но вы используете, например, LEFT JOIN, строки из таблицы students всё равно появятся, но информация из enrollments будет отсутствовать. Вместо конкретных данных в таких случаях появляются NULL.

Примерно так это выглядит:

Таблица students:

id name
1 Eva
2 Peter
3 Anna

Таблица enrollments:

student_id course_name
1 Математика
1 Информатика
2 Физика

Запрос с LEFT JOIN:

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

Результат:

id name course_name
1 Eva Математика
1 Eva Информатика
2 Peter Физика
3 Anna NULL

Ну, привет, NULL! Как видите, для Анны, которая не записана ни на один курс, информация о курсе отсутствует, и вместо чего-либо выводится NULL.

Как NULL влияет на запросы?

NULL — это не "ноль" и не "пустая строка", это отсутствие значения. Такое поведение имеет несколько интересных (и иногда раздражающих) последствий:

Сравнения с NULL:

Если вы напишете что-то вроде WHERE course_name = NULL, запрос не вернёт строк с NULL. Почему? Потому что с NULL нельзя сравнивать значения напрямую.

Чтобы проверить, есть ли NULL, нужно использовать специальные операторы:

WHERE course_name IS NULL

Математические операции:

Любая операция с NULL возвращает NULL. Например:

SELECT 5 + NULL; -- результат: NULL

Агрегатные функции:

Большинство агрегатных функций, таких как SUM(), AVG(), игнорируют NULL, но COUNT(*) считает их как "существующие строки".

Как бороться с NULL?

  1. Замена NULL на понятные значения с помощью COALESCE()

Функция COALESCE() позволяет заменить NULL другим значением. Например, если курс отсутствует, можно указать "Нет курса":

SELECT
    students.id, 
    students.name, 
    COALESCE(enrollments.course_name, 'Нет курса') AS course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id;

Результат:

id name course_name
1 Eva Математика
1 Eva Информатика
2 Peter Физика
3 Anna Нет курса

Теперь выглядит гораздо лучше, не правда ли?

  1. Фильтрация NULL значений

Если вы не хотите видеть строки с NULL, можно использовать условие WHERE ... IS NOT NULL. Например:

SELECT
    students.id, 
    students.name, 
    enrollments.course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id
WHERE 
    enrollments.course_name IS NOT NULL;

Результат:

id name course_name
1 Eva Математика
1 Eva Информатика
2 Peter Физика

Анна исчезает из результата, так как у неё отсутствуют записи на курсы.

  1. Считаем с учётом NULL: пример с COUNT

Как упоминалось ранее, некоторые функции игнорируют NULL, а некоторые нет. Например:

Чтобы посчитать все строки, включая те, где есть NULL:

SELECT COUNT(*) FROM students; -- Считает ВСЕ строки (включая те, где `course_name` = NULL)

Чтобы посчитать только строки, где нет NULL:

SELECT COUNT(course_name) FROM enrollments;
  1. Условные выражения с CASE

Если вам не нравится COALESCE() или вы хотите больше гибкости, попробуйте использовать CASE. Например:

SELECT
    students.id, 
    students.name,
    CASE
        WHEN enrollments.course_name IS NULL THEN 'Нет курса'
        ELSE enrollments.course_name
    END AS course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id;

Результат будет таким же, как при использовании COALESCE(), но CASE позволяет описывать более сложные правила.

  1. Используйте INNER JOIN, если уверены в отсутствии NULL

Самый радикальный способ избежать NULL — вообще не допускать их появления, используя INNER JOIN. Этот тип объединения возвращает только строки с совпадениями в обеих таблицах:

SELECT
    students.id, 
    students.name, 
    enrollments.course_name
FROM 
    students INNER JOIN enrollments 
    ON students.id = enrollments.student_id;

Без сюрпризов — только студенты, записанные на курсы.

Результат:

id name course_name
1 Eva Математика
1 Eva Информатика
2 Peter Физика

Если ваши данные требуют отображения всех значений, включая NULL, INNER JOIN не подойдёт, но иногда это всё, что нужно.

2
Задача
SQL SELF, 12 уровень, 0 лекция
Недоступна
Использование `COALESCE` для замены значений `NULL`
Использование `COALESCE` для замены значений `NULL`
2
Задача
SQL SELF, 12 уровень, 0 лекция
Недоступна
Подсчёт студентов без курсов (с использованием `COUNT`)
Подсчёт студентов без курсов (с использованием `COUNT`)
Комментарии (4)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Nkls Уровень 1
1 января 2026
SELECT COUNT(*) FROM students s LEFT JOIN enrollments e ON s.id = e.student_id WHERE e.course_name IS NULL Результат ноль Верно. Результат должен быть 1
Slevin Уровень 64
5 сентября 2025
Серьезно? 35й раз ОДНО И ТО ЖЕ про NULL? Ну сколько можно? P.S. А есть курс по NULL? Лекций на 400-500?
Vlad Tagunkov Уровень 28
26 декабря 2025
любой каприз за Ваши деньги 😂
Aleksandr Torhov Уровень 16
23 июля 2025
Админъ, просьба перепроверить, так как Left Join в данном случае должен вернуть все записи из таблицъ customers, а не enrollments