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