Почему сравнение с NULL в запросах 1С всегда возвращает ложь и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с языком запросов 1С начинающие разработчики часто сталкиваются с ситуацией, когда классические операторы сравнения (равно или не равно) ведут себя непредсказуемо при наличии пустых значений — это классический вопрос для тренировки перед собеседованием. Рассмотрим пример: в поле базы данных содержится NULL, и мы пытаемся проверить его с помощью конструкции КОГДА Поле = NULL ТОГДА 1 ИНАЧЕ 2. К удивлению программиста, система всегда возвращает 2. Разберем подробно, почему это происходит и как правильно работать с "пустотой" в реляционных базах данных.

Природа NULL и трехзначная логика

Для начала проанализируем, что такое NULL. В отличие от пустой строки, нуля или значения Неопределено, NULL в языке SQL и запросах 1С означает "отсутствие какого-либо значения" или "неизвестность". Это не объект и не число, это специальный маркер.

Основная проблема заключается в том, что 1С (вслед за стандартом SQL) использует так называемую трехзначную логику (3VL). В обычной логике выражение может быть либо истинным, либо ложным. В запросах же появляется третье состояние — UNKNOWN (Неизвестно).

  1. Любое сравнение с NULL (будь то =, <>, < или >) всегда возвращает NULL.
  2. Поскольку результат сравнения NULL = NULL — это "Неизвестно", условная конструкция ГДЕ или ВЫБОР воспринимает его как ЛОЖЬ, так как она пропускает только те записи, где условие равно строгой ИСТИНЕ.

Рассмотрим по шагам, что происходит в коде, который привел автор темы:


ВЫБРАТЬ
    ВЫБОР
        КОГДА Поле = NULL ТОГДА 1
        ИНАЧЕ 2
    КОНЕЦ

Когда система встречает строку, где Поле содержит NULL, она вычисляет NULL = NULL. Результат — NULL (Неизвестно). Условие КОГДА не выполняется, и управление переходит к ветке ИНАЧЕ. Именно поэтому мы всегда видим результат "2".

Правильный синтаксис: оператор ЕСТЬ NULL

Чтобы корректно определить, является ли значение в поле "пустым", мы должны использовать специальный предикат ЕСТЬ NULL (в английской версии IS NULL). Этот оператор специально предназначен для проверки наличия этого маркера, что особенно важно при интеграциях, например, при тестировании запросов к внешним системам.

Исправим наш пример, чтобы он работал ожидаемо:


ВЫБРАТЬ
    ВЫБОР
        КОГДА Поле ЕСТЬ NULL ТОГДА 1
        ИНАЧЕ 2
    КОНЕЦ

В этом случае проверка Поле ЕСТЬ NULL вернет логическую ИСТИНУ, и мы получим желаемый результат "1".

Различие между ЕСТЬ NULL и функцией ЕСТЬNULL()

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

  1. Оператор ЕСТЬ NULL: используется в условиях ГДЕ, ИМЕЮЩИЕ или в конструкциях ВЫБОР. Он возвращает булево значение.
  2. Функция ЕСТЬNULL(Значение, Замена): используется для подстановки альтернативного значения, если в первом параметре пришел NULL. Это критически важно при математических операциях.

Проанализируем ситуацию: мы складываем две колонки Сумма и Налог. Если в колонке Налог стоит NULL, результат всей суммы будет NULL, независимо от того, какое число в первой колонке. Чтобы избежать этого, применим функцию:


ВЫБРАТЬ
    ЕСТЬNULL(Таблица.Сумма, 0) + ЕСТЬNULL(Таблица.Налог, 0) КАК ИтоговаяСумма
ИЗ
    Справочник.Номенклатура КАК Таблица

NULL в агрегатных функциях

Выясним, как ведут себя итоги при наличии пустых значений. Это одна из самых полезных особенностей NULL в аналитике. Рассмотрим пример вычисления среднего арифметического. Предположим, у нас есть три строки со значениями: 10, 20 и NULL.

Агрегатные функции (СУММА, СРЕДНЕЕ, МИН, МАКС) полностью игнорируют NULL-значения:

Это коренное отличие NULL от нуля. Если бы вместо NULL стоял 0, то среднее было бы равно 10 (30 / 3).

Сложные случаи: сравнение через "НЕ"

Рассмотрим еще одну ловушку, в которую попадают разработчики. Проанализируем запрос с отрицанием:

ВЫБРАТЬ * ИЗ РегистрНакопления.Продажи ГДЕ НЕ (Цена = 0)

Если в поле Цена стоит NULL, попадет ли эта строка в результат? Нет. Потому что NULL = 0 дает NULL, отрицание НЕ NULL снова дает NULL. В итоге условие ГДЕ не получает ИСТИНУ и отбрасывает строку. Если вы хотите видеть и те строки, где цена не задана, условие нужно писать явно:

ГДЕ (НЕ Цена = 0) ИЛИ (Цена ЕСТЬ NULL)

Таблицы истинности для NULL

Для лучшего понимания работы логических операторов с неизвестными значениями, разберем таблицы истинности. Обозначим NULL как "Н" (Неизвестно).

Логическое И (AND):

Логическое ИЛИ (OR):

Важный момент: Как мы видим, выражение ИСТИНА ИЛИ NULL возвращает ИСТИНА. Это часто используется оптимизаторами запросов для ускорения вычислений.

Источники появления NULL в 1С

В системе 1С:Предприятие NULL чаще всего появляется не сам по себе, а в результате работы механизмов платформы. Разберем основные причины:

  1. Левое соединение (LEFT JOIN): Это самый массовый источник, особенно в отчетах. Глубокое понимание соединений критично при программной работе с СКД. Когда мы соединяем две таблицы и во второй таблице нет соответствующей записи, все поля этой таблицы заполняются NULL.
  2. Обращение через точку: Если мы обращаемся к реквизиту ссылки, которой не существует (битая ссылка) или которая имеет составной тип и не заполнена, в запросе мы получим NULL.
  3. Итоги в запросах: В иерархических итогах поля, по которым не производилась группировка, на уровнях иерархии будут содержать NULL.

Рекомендации по практике

Подводя итог нашему разбору (глубже подобные темы для разработчиков разбираются в докладах с профильных конференций), выделим основные правила безопасной работы с пустотой в запросах:

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

← На главную