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