В КУРСЕ?

Разбираемся в теме

SQL считает лишнюю задачу: почему после LEFT JOIN ноль превращается в единицу?

В отчёте по проектам нужно показать число задач, включая проекты, у которых задач пока нет. Кажется, достаточно соединить две таблицы и посчитать строки. Однако рядом с пустым проектом неожиданно появляется единица. Чтобы понять причину, полезно сначала представить промежуточную таблицу, а уже затем выбирать функцию подсчёта.

Какую строку сохраняет соединение

Пусть в таблице проектов есть Город с номером 10, Лес с номером 20 и Море с номером 30. У Города две задачи, у Моря одна, у Леса ни одной. Каждая задача имеет собственный непустой идентификатор и номер проекта. LEFT JOIN сохраняет все проекты из левой таблицы. Для Города он создаёт две строки, для Моря одну. Для Леса тоже остаётся строка, но значения полей задачи в ней будут NULL. Это обозначение отсутствующего значения, а не настоящая задача с пустым названием.

Что именно считает COUNT

После группировки по идентификатору проекта COUNT(*) считает строки внутри каждой группы. Получаются значения 2, 1 и 1. Функция исправна: у Леса действительно есть одна строка промежуточного результата. Если считать COUNT(task.id), учитываются только строки с непустым идентификатором задачи. Тогда результат равен 2, 0 и 1. Здесь принципиально, что у настоящей задачи выбранное поле не бывает NULL. Подсчёт необязательного комментария мог бы пропустить существующую задачу без комментария. Сначала определите сущность, которую считаете, затем выберите её надёжный признак.

Почему положение фильтра меняет отчёт

Теперь нужна численность только завершённых задач. Пусть у Города завершена одна задача, остальные задачи ещё выполняются. Если требование к статусу входит в условие ON вместе со связью по проекту, соединение сохраняет все проекты и подбирает только подходящие задачи. Получатся значения 1, 0 и 0. Если после соединения поставить в WHERE условие равенства статуса завершённому, строки без подходящей задачи не пройдут фильтр. Лес и Море исчезнут. Это разные вопросы: какие проекты имеют завершённые задачи и сколько таких задач есть у каждого проекта.

Проверяйте промежуточный результат

До добавления группировки выпишите рядом номер проекта, номер задачи и её статус. Такая проверка показывает, где появилась дополнительная строка, а где исчез весь проект. Полезный проверочный набор содержит пустой проект, проект с несколькими задачами и проект без задач нужного статуса. Ещё одна причина завышения числа возникает при присоединении других таблиц: например, несколько комментариев могут размножить одну задачу. Тогда нужно заново проверить уровень детализации результата, а не механически заменять одну форму COUNT другой.

Попробуйте на практике

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

  1. Запишите проекты 10, 20 и 30. Добавьте задачи 1 и 2 проекту 10, задачу 3 проекту 30.
  2. Назначьте задаче 1 завершённый статус, а задачам 2 и 3 незавершённый.
  3. Нарисуйте четыре строки результата LEFT JOIN без фильтра, включая строку проекта 20 с отсутствующей задачей.
  4. Для каждого проекта отдельно посчитайте все строки и непустые номера задач.
  5. Повторите соединение с отбором завершённых задач внутри ON, затем мысленно перенесите этот отбор в WHERE.

Как проверить результат. Первый подсчёт даёт 2, 1, 1, второй 2, 0, 1. Отбор внутри ON оставляет три проекта с результатом 1, 0, 0; отбор в WHERE оставляет только проект 10.

Частые вопросы

NULL означает число ноль?

Нет. NULL обозначает отсутствующее или неизвестное значение. Ноль является конкретным числовым значением и учитывается функцией COUNT выражения, если само выражение не равно NULL.

Достаточно группировать по названию проекта?

Только если уникальность названия гарантирована. Разные проекты могут называться одинаково. Для сохранения их самостоятельности группировку строят с учётом уникального идентификатора.

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

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

Зарегистрироваться
← К списку материалов