Наверняка каждый разработчик 1С сталкивался с ситуацией, когда поле в запросе или в данных выглядит абсолютно пустым, но при попытке проверить его на NULL с помощью оператора IS NULL или ЕСТЬ NULL мы получаем неожиданное ЛОЖЬ. Это приводит в замешательство и заставляет задуматься: что же это за "NULL, который не NULL"? Давайте вместе разберемся в этой распространенной проблеме и выясним, как правильно работать с различными видами "пустых" значений в 1С.
Чтобы подойти к решению, мы проанализируем несколько ключевых понятий, которые часто путают с истинным NULL, а также рассмотрим конкретные инструменты и методы, которые помогут нам в работе.
Начнем с самого понятия NULL в контексте 1С и баз данных. Истинный NULL – это специальное значение, которое обозначает отсутствие значения. Оно не равно нулю, пустой строке, пустой ссылке или любому другому значению. NULL имеет свой собственный тип – Null.
Когда появляется истинный NULL?
NULL в результатах запросов, использующих ЛЕВОЕ СОЕДИНЕНИЕ, ПРАВОЕ СОЕДИНЕНИЕ или ПОЛНОЕ СОЕДИНЕНИЕ. Если для записи из одной таблицы не найдено соответствующей записи в другой, поля второй таблицы для этой строки будут содержать NULL.NULL.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. Мы еще вернемся к этому моменту.
Помимо истинного NULL, в 1С существует другое специальное значение – Неопределено. Это значение относится к встроенному языку 1С и обозначает неопределенное значение. Оно имеет тип Неопределено.
Когда возникает Неопределено?
Неопределено чаще всего используется как значение по умолчанию для реквизитов (или колонок таблиц значений), имеющих составной тип, то есть способных хранить значения нескольких типов. Например, если реквизит может быть и строкой, и числом, и ссылкой, при его создании по умолчанию он часто будет иметь значение Неопределено.
Важно: Неопределено – это не то же самое, что и NULL. Это два разных типа значений, и они ведут себя по-разному при проверках.
Для большинства простых типов данных в 1С существуют так называемые "пустые значения". Это значения по умолчанию для конкретного типа, которые не являются ни NULL, ни Неопределено. Они являются полноценными значениями своего типа, просто "пустыми" по смыслу.
Рассмотрим несколько примеров:
0 (ноль)."".00010101.Значение(Справочник.ИмяСправочника.ПустаяСсылка).Если в вашем Поле2 содержится, например, пустая строка "", то КлючиДоступаКРегистрам.Поле2 IS NULL вернет ЛОЖЬ, потому что "" – это не NULL, а конкретное строковое значение. То же самое относится к 0 для чисел или пустой ссылке.
В вашем запросе мы видим еще одну интересную строку: КлючиДоступаКРегистрам.Поле2 = Значение(Перечисление.ДополнительныеЗначенияДоступа.NULL) КАК ЭтоЗначениеПеречисления.
Здесь мы видим сравнение поля с конкретным значением из перечисления, которое просто имеет имя "NULL". Это не является системным NULL из базы данных. Это обычное значение перечисления, которое разработчик назвал NULL. Сравнение с таким значением будет работать стандартным образом, как и любое другое сравнение с элементом перечисления. Если Поле2 содержит именно это значение перечисления, то колонка ЭтоЗначениеПеречисления вернет ИСТИНА.
Чтобы точно определить, что находится в вашем поле, когда оно кажется "пустым", но не является NULL, мы можем использовать несколько подходов.
Как справедливо отметили участники форума, Консоль запросов из Инструментов разработчика – это наш лучший друг в таких ситуациях. Запустив ваш запрос в консоли, мы можем увидеть не только значения в колонках, но и их типы. Это критически важно!
Колонка ТипЗначения(КлючиДоступаКРегистрам.Поле2) в вашем запросе уже помогает нам в этом. Если в консоли запросов мы увидим, что для "пустого" поля:
Null, то это истинный NULL.Неопределено, то это значение Неопределено.Число, а значение 0, то это "пустое число".Строка, а значение "", то это "пустая строка".ПеречислениеСсылка.ДополнительныеЗначенияДоступа, а значение NULL, то это элемент перечисления.Существуют также портативные универсальные инструменты, которые предоставляют расширенный функционал для работы с запросами и анализа типов данных, что может быть очень удобно.
Для удобной работы с истинным NULL в запросах 1С, когда мы хотим заменить его на какое-либо значение по умолчанию, мы используем функцию ЕСТЬNULL.
Синтаксис: ЕСТЬNULL(<Проверяемое выражение>, <Выражение замены>)
Эта функция возвращает значение первого параметра, если оно не NULL. Если же первый параметр содержит NULL, функция возвращает значение второго параметра.
Посмотрим на примеры использования:
NULL на 0 для числовых полей:
ВЫБРАТЬ
ЕСТЬNULL(Таблица.ЧисловоеПоле, 0) КАК ЧислоБезНУЛЛ
ИЗ
ВашаТаблица КАК Таблица
NULL на пустую строку для строковых полей:
ВЫБРАТЬ
ЕСТЬNULL(Таблица.СтроковоеПоле, "") КАК СтрокаБезНУЛЛ
ИЗ
ВашаТаблица КАК Таблица
NULL на пустую ссылку для ссылочных полей:
ВЫБРАТЬ
ЕСТЬNULL(Таблица.СсылкаНаСправочник, Значение(Справочник.ВашСправочник.ПустаяСсылка)) КАК СсылкаБезНУЛЛ
ИЗ
ВашаТаблица КАК Таблица
Используя ЕСТЬNULL, мы можем гарантировать, что в результирующей выборке не будет истинных NULL, что упрощает дальнейшую обработку данных во встроенном языке.
Итак, мы выяснили, что "NULL, который не NULL" – это не мистика, а результат существования нескольких различных концепций "пустоты" в 1С. Чтобы избежать путаницы, всегда помните:
NULL – это отсутствие значения из БД, проверяется только через ЕСТЬ NULL / IS NULL.Неопределено – это значение встроенного языка, чаще всего для составных типов.0, "", ПустаяСсылка).Активно используйте консоль запросов для анализа типов данных и функцию ЕСТЬNULL для обработки истинных NULL в запросах. Такой подход позволит вам писать более надежный и предсказуемый код.