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