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