В процессе разработки отчетов на Системе Компоновки Данных (СКД) мы часто сталкиваемся с задачей условного вывода данных. Типичный сценарий: если основное поле не заполнено, нужно вывести значение из другого (резервного) поля. Однако при реализации этой логики многие допускают ошибки, связанные с типизацией данных в языке запросов 1С.
Разберем подробно проблему, с которой столкнулся автор темы: попытку сравнения ссылочного поля со строкой и неправильное использование функции ЕСТЬNULL. Мы выясним, почему конструкция ВЫБОР КОГДА ... = "" не работает для справочников, и научимся писать корректные запросы.
В исходном коде мы видим следующую конструкцию внутри запроса:
ВЫБОР
КОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизацииЗавершения = ""
ТОГДА ...
ИНАЧЕ ...
КОНЕЦ
Автор пытается проверить, заполнено ли поле ПодразделениеОрганизацииЗавершения, сравнивая его с пустой строкой (""). Это фундаментальная ошибка.
В языке запросов 1С (как и во встроенном языке) действует строгая типизация. Поле ПодразделениеОрганизацииЗавершения имеет тип СправочникСсылка (например, Ссылка на справочник Подразделения). А литерал "" имеет тип Строка.
При выполнении условия Ссылка = Строка система 1С всегда возвращает результат Ложь, потому что эти типы данных никогда не могут быть равны друг другу. Даже если пользователю кажется, что поле "пустое", технически там находится "Пустая ссылка", а не пустая строка. Именно поэтому условие КОГДА не срабатывает, и всегда выполняется ветка ИНАЧЕ.
Чтобы правильно составить условие, нам нужно четко понимать, что именно хранится в базе данных, когда поле "не заполнено". Рассмотрим три состояния "пустоты":
NULL появляется, как правило, в результате соединения таблиц (левое или полное соединение), когда для записи из одной таблицы не нашлось соответствия в другой. Если вы просто читаете данные из одной таблицы (например, СрезПоследних), значение NULL там встретится вряд ли, если только само поле не является составным типом, который не был инициализирован.
Функция ЕСТЬNULL (или ISNULL) работает только с типом NULL. Она бесполезна для проверки Пустой ссылки.
Чтобы проверить, заполнено ли поле ссылочного типа, мы должны сравнивать его не со строкой, а с предопределенным значением пустой ссылки того же типа. Для этого в языке запросов используется конструкция ЗНАЧЕНИЕ(...).
Рассмотрим, как правильно переписать условие для справочника подразделений:
ВЫБОР
КОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизацииЗавершения = ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)
ТОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации
ИНАЧЕ РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизацииЗавершения
КОНЕЦ КАК Подразделение
В этом случае мы сравниваем Ссылку со Ссылкой. Такое условие отработает корректно.
В сложных запросах, особенно где присутствуют соединения таблиц, поле может оказаться как NULL (нет записи), так и ПустойСсылкой (запись есть, но поле не заполнено).
Чтобы гарантированно подставить альтернативное значение, нам нужно учесть оба варианта. Разберем наиболее надежный способ написания запроса.
Мы можем сначала превратить потенциальный NULL в пустую ссылку, а затем проверить результат на равенство пустой ссылке.
ВЫБОР
// Сначала преобразуем NULL в пустую ссылку, затем проверяем на пустоту
КОГДА ЕСТЬNULL(РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизацииЗавершения, ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)) = ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)
ТОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации
ИНАЧЕ РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизацииЗавершения
КОНЕЦ
Этот способ часто более читаем и понятен при отладке:
ВЫБОР
КОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизацииЗавершения ЕСТЬ NULL
ИЛИ РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизацииЗавершения = ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)
ТОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации
ИНАЧЕ РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизацииЗавершения
КОНЕЦ
Если поле ПодразделениеОрганизацииЗавершения имеет составной тип (может хранить ссылки на разные справочники), проверка усложняется. Сравнение с пустой ссылкой конкретного справочника может не сработать, если в поле записана пустая ссылка другого типа или значение Неопределено.
В таких случаях лучше проверять "от обратного" — что значение заполнено, или использовать оператор ССЫЛКА, если нас интересует конкретный тип. Однако самый простой вариант для составных типов в запросе — проверить на Неопределено, если это допустимо логикой:
... ГДЕ Поле = ЗНАЧЕНИЕ(Неопределено) ...
Если вы не хотите усложнять текст SQL-запроса, Система Компоновки Данных позволяет решить эту задачу на уровне настроек — через Вычисляемые поля.
В языке выражений СКД (не путать с языком запросов) есть очень удобная функция ЗначениеЗаполнено(). Она универсальна: она возвращает Ложь для NULL, Неопределено, пустых ссылок, пустых строк, нуля и ложи.
Вы можете создать вычисляемое поле, например ИтоговоеПодразделение, и прописать в выражении:
ВЫБОР
КОГДА ЗначениеЗаполнено(ПодразделениеОрганизацииЗавершения)
ТОГДА ПодразделениеОрганизацииЗавершения
ИНАЧЕ ПодразделениеОрганизации
КОНЕЦ
Этот подход часто бывает предпочтительнее, так как он разгружает запрос к базе данных и делает логику отчета более гибкой для настройки пользователем.
Подведем итог, как избежать ошибки с пустыми строками в отчетах:
"". Это сравнение всегда дает Ложь.ЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка).ЕСТЬNULL заменяет только технический NULL (отсутствие записи), но не заменяет пустую ссылку.ЗначениеЗаполнено() для универсальной проверки.