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