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