При работе с языком запросов 1С начинающие и даже опытные разработчики часто сталкиваются с нюансами обработки пустого значения NULL. На первый взгляд может показаться странным, что выражения ВЫБРАТЬ НЕ ("Значение" ЕСТЬ NULL) и "Значение" ЕСТЬ НЕ NULL работают идентично. Более того, попытка использовать НЕ NULL как самостоятельное выражение часто приводит к неожиданным результатам. В этой статье мы подробно разберем внутреннюю логику работы этих конструкций, опираясь на стандарты SQL и особенности реализации в платформе 1С.
Для того чтобы понять, как система обрабатывает NULL, нам необходимо рассмотреть фундаментальную концепцию — трехзначную логику (Three-Valued Logic или 3VL). В классическом программировании мы привыкли к двум состояниям: Истина (TRUE) и Ложь (FALSE). Однако в базах данных существует третье состояние — Неизвестно (UNKNOWN), которое и представляет собой NULL.
Разберем, как работают логические операции в этой системе:
NULL (например, Реквизит = NULL) всегда возвращает NULL (неизвестность), а не истину или ложь.НЕ (NOT) применительно к NULL также возвращает NULL.ЕСТЬ NULL и ЕСТЬ НЕ NULL — это специальные инструменты, предназначенные для того, чтобы «вывести» неопределенность в область двузначной логики (Истина/Ложь).Проанализируем ситуацию, описанную в сообщениях форума. Проблема понимания часто кроется в том, что разработчики воспринимают НЕ как унарную операцию, которая должна выполняться первой. Однако в языке SQL (на котором базируются запросы 1С) существует четкое разделение.
Предикат — это выражение, которое возвращает логическое значение. Конструкции ЕСТЬ NULL и ЕСТЬ НЕ NULL являются неделимыми предикатами. Когда мы пишем ЕСТЬ НЕ NULL, парсер запроса не видит здесь отдельно оператор ЕСТЬ и отдельно отрицание НЕ. Он воспринимает это как единую синтаксическую единицу проверки — null predicate.
Рассмотрим разницу в выполнении двух вариантов:
Рассмотрим по шагам процесс вычисления:
Поле ЕСТЬ NULL. Результатом будет либо Истина (если в поле действительно NULL), либо Ложь (если там любое другое значение).НЕ к полученному булеву значению. НЕ Истина превращается в Ложь, а НЕ Ложь — в Истина.Здесь ситуация иная:
NULL, результат — Ложь.Как видим, итоговый результат идентичен, но пути его достижения разные. С точки зрения чистоты кода и читаемости, вариант ЕСТЬ НЕ NULL предпочтительнее, так как он более наглядно описывает суть проверки.
Одним из самых запутанных моментов в обсуждении стала конструкция НЕ NULL ЕСТЬ НЕ NULL. Давайте выясним причину, по которой она интерпретируется системой именно так, а не иначе. Проанализируем ситуацию, разбив выражение на составляющие части в соответствии с приоритетами операций.
Согласно стандартам, предикаты сравнения имеют более высокий приоритет, чем логическое НЕ. Однако в данном случае НЕ стоит в начале выражения и относится к литералу NULL. Разберем последовательность:
Первым шагом вычисляется левая часть выражения — НЕ NULL. Как мы уже выяснили выше, отрицание неизвестности (NULL) дает ту же самую неизвестность (NULL). Таким образом, выражение упрощается до:
NULL ЕСТЬ НЕ NULL
Далее применяется предикат ЕСТЬ НЕ NULL к значению NULL. Поскольку значение является пустым, проверка на «не-пустоту» возвращает Ложь.
Если мы попытаемся записать это в виде кода запроса, это будет выглядеть примерно так:
ВЫБРАТЬ
ВЫБОР
КОГДА НЕ NULL ЕСТЬ НЕ NULL ТОГДА "Истина"
ИНАЧЕ "Ложь"
КОНЕЦ КАК Результат
Во многих языках программирования и стандартах SQL приоритет логических операций может варьироваться. В 1С рекомендуется придерживаться следующих правил, чтобы избежать неоднозначности:
И, ИЛИ и НЕ совместно с предикатами ЕСТЬ NULL.ЕСТЬ NULL — это не просто сравнение через знак равенства, а проверка состояния объекта в памяти базы данных.Поле = NULL, так как она всегда будет возвращать Ложь в условиях ГДЕ (поскольку NULL в логическом контексте трактуется как отсутствие Истины).Посмотрим на пример правильного написания сложных условий:
ГДЕ
(ТоварыНаСкладах.Остаток > 0)
И (НЕ ТоварыНаСкладах.Номенклатура ЕСТЬ NULL)
И (ТоварыНаСкладах.Склад ЕСТЬ НЕ NULL)
Часто возникает вопрос: влияет ли выбор между НЕ (... ЕСТЬ NULL) и ... ЕСТЬ НЕ NULL на скорость выполнения запроса? С точки зрения современных СУБД, таких как MS SQL Server или PostgreSQL, разницы в производительности нет. Оптимизатор запросов (Query Optimizer) на этапе построения плана выполнения преобразует обе эти конструкции в одну и ту же низкоуровневую операцию проверки существования значения в ячейке или проверки индекса.
Однако стоит помнить о «житейской логике», упомянутой в дискуссии. Использование канонической формы ЕСТЬ НЕ NULL снижает когнитивную нагрузку на программиста, который будет читать ваш код позже. Ему не придется в уме инвертировать результат проверки, что уменьшает вероятность логических ошибок при доработке запроса.
Подводя итог нашему разбору, можно выделить ключевые моменты:
NULL — это не значение «0» или «пустая строка», а индикатор отсутствия данных.НЕ NULL всегда возвращает NULL из-за правил трехзначной логики.ЕСТЬ НЕ NULL — это единый предикат, а не комбинация из двух разных операторов.ЕСТЬ NULL и ЕСТЬ НЕ NULL вместо попыток сравнения через = или использования НЕ напрямую к NULL.Применяя эти знания на практике, вы сможете писать более надежные и понятные запросы, избегая «костылей» и неоднозначных трактовок логических выражений.