Почему поле в 1С кажется пустым, но проверка IS NULL возвращает ЛОЖЬ? Разбираем "NULL, который не NULL"

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием
← К списку

Наверняка каждый разработчик 1С сталкивался с ситуацией, когда поле в запросе или в данных выглядит абсолютно пустым, но при попытке проверить его на NULL с помощью оператора IS NULL или ЕСТЬ NULL мы получаем неожиданное ЛОЖЬ. Это приводит в замешательство и заставляет задуматься: что же это за "NULL, который не NULL"? Давайте вместе разберемся в этой распространенной проблеме и выясним, как правильно работать с различными видами "пустых" значений в 1С.

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

1. Истинный NULL: когда он возникает и как его проверять

Начнем с самого понятия NULL в контексте 1С и баз данных. Истинный NULL – это специальное значение, которое обозначает отсутствие значения. Оно не равно нулю, пустой строке, пустой ссылке или любому другому значению. NULL имеет свой собственный тип – Null.

Когда появляется истинный NULL?

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

Как правильно проверять на NULL?

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

Почему сравнение Поле = NULL не работает?

В SQL, и соответственно в запросах 1С, любая операция сравнения с NULL (даже NULL = NULL) дает результат UNKNOWN (неизвестно), который в 1С интерпретируется как ЛОЖЬ. Именно поэтому, если вы пытаетесь проверить поле на NULL с помощью конструкции Поле = Значение(Null), вы всегда получите ЛОЖЬ, даже если поле действительно содержит NULL.

Давайте посмотрим на пример запроса, который вы предоставили, и проанализируем его:


ВЫБРАТЬ ПЕРВЫЕ 10
	КлючиДоступаКРегистрам.Регистр КАК Регистр,
	КлючиДоступаКРегистрам.ВариантДоступа КАК ВариантДоступа,
	КлючиДоступаКРегистрам.Поле1 КАК Поле1,
	ТипЗначения(КлючиДоступаКРегистрам.Поле2),
	КлючиДоступаКРегистрам.Поле2 КАК Поле2,
	КлючиДоступаКРегистрам.Поле2 IS NULL КАК ЭтоНУЛЛ,
	КлючиДоступаКРегистрам.Поле2 = Значение(Перечисление.ДополнительныеЗначенияДоступа.NULL) КАК ЭтоЗначениеПеречисления,
	КлючиДоступаКРегистрам.КлючДоступа КАК КлючДоступа
ИЗ
	РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам

В этом запросе колонка ЭтоНУЛЛ использует правильный оператор IS NULL. Если значение в Поле2 действительно является истинным NULL, то ЭтоНУЛЛ вернет ИСТИНА. Если же оно содержит что-то другое (даже если это "пустое" значение другого типа), то ЭтоНУЛЛ вернет ЛОЖЬ. Колонка ТипЗначения(КлючиДоступаКРегистрам.Поле2) также очень информативна: для истинного NULL она вернет NULL. Мы еще вернемся к этому моменту.

2. Значение Неопределено: когда оно используется

Помимо истинного NULL, в 1С существует другое специальное значение – Неопределено. Это значение относится к встроенному языку 1С и обозначает неопределенное значение. Оно имеет тип Неопределено.

Когда возникает Неопределено?

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

Важно: Неопределено – это не то же самое, что и NULL. Это два разных типа значений, и они ведут себя по-разному при проверках.

3. "Пустые значения" типов данных: не NULL и не Неопределено

Для большинства простых типов данных в 1С существуют так называемые "пустые значения". Это значения по умолчанию для конкретного типа, которые не являются ни NULL, ни Неопределено. Они являются полноценными значениями своего типа, просто "пустыми" по смыслу.

Рассмотрим несколько примеров:

  1. Числовые поля: Пустое значение для числа – это 0 (ноль).
  2. Строковые поля: Пустое значение для строки – это пустая строка "".
  3. Поля типа "Дата": Пустое значение для даты – это дата начала отсчета, обычно 00010101.
  4. Ссылочные типы (справочники, документы, перечисления и т.д.): Пустое значение для ссылочных типов – это пустая ссылка соответствующего типа. Например, Значение(Справочник.ИмяСправочника.ПустаяСсылка).

Если в вашем Поле2 содержится, например, пустая строка "", то КлючиДоступаКРегистрам.Поле2 IS NULL вернет ЛОЖЬ, потому что "" – это не NULL, а конкретное строковое значение. То же самое относится к 0 для чисел или пустой ссылке.

4. Особый случай: Значение(Перечисление.ДополнительныеЗначенияДоступа.NULL)

В вашем запросе мы видим еще одну интересную строку: КлючиДоступаКРегистрам.Поле2 = Значение(Перечисление.ДополнительныеЗначенияДоступа.NULL) КАК ЭтоЗначениеПеречисления.

Здесь мы видим сравнение поля с конкретным значением из перечисления, которое просто имеет имя "NULL". Это не является системным NULL из базы данных. Это обычное значение перечисления, которое разработчик назвал NULL. Сравнение с таким значением будет работать стандартным образом, как и любое другое сравнение с элементом перечисления. Если Поле2 содержит именно это значение перечисления, то колонка ЭтоЗначениеПеречисления вернет ИСТИНА.

5. Инструменты для отладки и решения проблемы

Чтобы точно определить, что находится в вашем поле, когда оно кажется "пустым", но не является NULL, мы можем использовать несколько подходов.

5.1. Анализ типа значения с помощью консоли запросов

Как справедливо отметили участники форума, Консоль запросов из Инструментов разработчика – это наш лучший друг в таких ситуациях. Запустив ваш запрос в консоли, мы можем увидеть не только значения в колонках, но и их типы. Это критически важно!

Колонка ТипЗначения(КлючиДоступаКРегистрам.Поле2) в вашем запросе уже помогает нам в этом. Если в консоли запросов мы увидим, что для "пустого" поля:

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

5.2. Обработка NULL в запросах с помощью ЕСТЬNULL

Для удобной работы с истинным NULL в запросах 1С, когда мы хотим заменить его на какое-либо значение по умолчанию, мы используем функцию ЕСТЬNULL.

Синтаксис: ЕСТЬNULL(<Проверяемое выражение>, <Выражение замены>)

Эта функция возвращает значение первого параметра, если оно не NULL. Если же первый параметр содержит NULL, функция возвращает значение второго параметра.

Посмотрим на примеры использования:

  1. Замена NULL на 0 для числовых полей:
    
    ВЫБРАТЬ
        ЕСТЬNULL(Таблица.ЧисловоеПоле, 0) КАК ЧислоБезНУЛЛ
    ИЗ
        ВашаТаблица КАК Таблица
    
  2. Замена NULL на пустую строку для строковых полей:
    
    ВЫБРАТЬ
        ЕСТЬNULL(Таблица.СтроковоеПоле, "") КАК СтрокаБезНУЛЛ
    ИЗ
        ВашаТаблица КАК Таблица
    
  3. Замена NULL на пустую ссылку для ссылочных полей:
    
    ВЫБРАТЬ
        ЕСТЬNULL(Таблица.СсылкаНаСправочник, Значение(Справочник.ВашСправочник.ПустаяСсылка)) КАК СсылкаБезНУЛЛ
    ИЗ
        ВашаТаблица КАК Таблица
    

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

Заключение

Итак, мы выяснили, что "NULL, который не NULL" – это не мистика, а результат существования нескольких различных концепций "пустоты" в 1С. Чтобы избежать путаницы, всегда помните:

Активно используйте консоль запросов для анализа типов данных и функцию ЕСТЬNULL для обработки истинных NULL в запросах. Такой подход позволит вам писать более надежный и предсказуемый код.

← К списку