Как в отчете СКД вывести колонки за два разных периода друг за другом помесячно?

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При разработке аналитических отчетов в схеме компоновки данных часто возникает задача план-фактного анализа или сравнения показателей за аналогичные периоды разных лет (например, первый квартал прошлого года против первого квартала текущего года). Типичная проблема заключается в том, что при стандартном добавлении двух периодов в колонки таблицы компоновщик выводит сначала все месяцы первого интервала, а затем все месяцы второго. Рассмотрим причины такого поведения и разберем практические способы настройки отчета, при которых одноименные месяцы выводятся рядом друг с другом, а также рассчитывается разница между ними.

Почему СКД выводит периоды последовательно

Проанализируем логику работы механизма компоновки данных. Когда в область колонок таблицы СКД добавляются два независимых поля (например, ПериодМесяц и ПериодМесяцДоп), система обрабатывает их последовательно. Платформа сначала строит дерево колонок по первому полю, а затем пристыковывает дерево колонок по второму полю. Обычная сортировка не способна объединить значения из двух разных реквизитов в общую чередующуюся цепочку.

Чтобы получить вывод вида «Январь 2022 — Январь 2023 — Февраль 2022 — Февраль 2023», необходимо предоставить СКД единую координатную сетку. Выясним, какими путями можно решить эту задачу без использования программной доработки процессора вывода.

Способ 1. Приведение к единой шкале через объединение запросов

Разберем по шагам наиболее производительный и гибкий способ, основанный на объединении двух выборок через оператор ОБЪЕДИНИТЬ ВСЕ. В этом варианте мы не делаем тяжелых соединений таблиц, а создаем сквозную группировку.

  1. Формирование единой структуры полей в запросе. Приведем наименования показателей к единому виду и введем поле относительного номера месяца:

ВЫБРАТЬ
	НАЧАЛОПЕРИОДА(ГпОтгрузка.Период, МЕСЯЦ) КАК ПериодМесяц,
	МЕСЯЦ(ГпОтгрузка.Период) КАК НомерМесяца,
	1 КАК НомерПериода,
	ГпОтгрузка.ГпТранспортнаяУпаковка КАК ТранспортнаяУпаковка,
	ГпОтгрузка.ГпТранспортнаяУпаковка.СсылкаГпАналитикаГруппа.СсылкаПодразделенияПроизводственныеЦеха КАК Цех,
	ГпОтгрузка.Вес * &КоэффициентИзмерения КАК Вес,
	ГпОтгрузка.СуммаСоСкидкой КАК СуммаСоСкидкой
ИЗ
	РегистрНакопления.ГпОтгрузка КАК ГпОтгрузка
ГДЕ
	ГпОтгрузка.Период МЕЖДУ &ДатаНачала И &ДатаОкончания

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	НАЧАЛОПЕРИОДА(ГпОтгрузка.Период, МЕСЯЦ) КАК ПериодМесяц,
	МЕСЯЦ(ГпОтгрузка.Период) КАК НомерМесяца,
	2 КАК НомерПериода,
	ГпОтгрузка.ГпТранспортнаяУпаковка КАК ТранспортнаяУпаковка,
	ГпОтгрузка.ГпТранспортнаяУпаковка.СсылкаГпАналитикаГруппа.СсылкаПодразделенияПроизводственныеЦеха КАК Цех,
	ГпОтгрузка.Вес * &КоэффициентИзмерения КАК Вес,
	ГпОтгрузка.СуммаСоСкидкой КАК СуммаСоСкидкой
ИЗ
	РегистрНакопления.ГпОтгрузка КАК ГпОтгрузка
ГДЕ
	ГпОтгрузка.Период МЕЖДУ &ДатаНачалаДоп И &ДатаОкончанияДоп

Если интервалы сравнения начинаются с разных месяцев года (например, ноябрь одного года и май другого), вместо функции МЕСЯЦ() используем вычисление смещения через РАЗНОСТЬДАТ(&ДатаНачала, ГпОтгрузка.Период, МЕСЯЦ) для первого запроса и аналогичную разность с параметром &ДатаНачалаДоп для второго.

  1. Настройка структуры отчета. В структуре таблицы в область колонок поместим родительскую группировку по полю НомерМесяца. Внутрь нее добавим подчиненную группировку колонок по полю ПериодМесяц. Таким образом, СКД сначала сгруппирует колонки по порядковому номеру (1 — Январь, 2 — Февраль и т.д.), а внутри каждого номера расположит колонки конкретных дат обоих периодов.
  2. Расчет разницы между колонками. Так как показатели первого и второго периода находятся в разных строках выборки, стандартное вычитание ресурсов «в лоб» не сработает. На вкладке Ресурсы для поля отклонения применим специализированную функцию СКД:

ВычислитьВыражение("Сумма(Вес)", "ПериодМесяц", "Группировка", "Последняя") - ВычислитьВыражение("Сумма(Вес)", "ПериодМесяц", "Группировка", "Первая")

Это выражение берет значение последнего периода в рамках текущего месяца и вычитает из него показатель первого периода, обеспечивая правильный расчет отклонения.

Способ 2. Полное соединение во временных таблицах

Рассмотрим альтернативный вариант, когда расчет отклонения требуется получить максимально прозрачно с помощью стандартных числовых ресурсов без использования сложных функций компоновки. Этот подход удобен, если число аналитик невелико и требуется жестко зафиксировать вывод колонок Вес 1, Вес 2 и Отклонение под общим заголовком каждого месяца.

  1. Подготовка временных таблиц в запросе. Сгруппируем данные по каждому периоду отдельно в разрезе аналитик и относительного месяца, после чего свяжем их через ПОЛНОЕ СОЕДИНЕНИЕ:

ВЫБРАТЬ
	МЕСЯЦ(ГпОтгрузка.Период) КАК НомерМесяца,
	ГпОтгрузка.ГпТранспортнаяУпаковка КАК ТранспортнаяУпаковка,
	ГпОтгрузка.ГпТранспортнаяУпаковка.СсылкаГпАналитикаГруппа.СсылкаПодразделенияПроизводственныеЦеха КАК Цех,
	СУММА(ГпОтгрузка.Вес * &КоэффициентИзмерения) КАК ВесПериод1
ПОМЕСТИТЬ ВТ_Период1
ИЗ
	РегистрНакопления.ГпОтгрузка КАК ГпОтгрузка
ГДЕ
	ГпОтгрузка.Период МЕЖДУ &ДатаНачала И &ДатаОкончания
СГРУППИРОВАТЬ ПО
	МЕСЯЦ(ГпОтгрузка.Период),
	ГпОтгрузка.ГпТранспортнаяУпаковка,
	ГпОтгрузка.ГпТранспортнаяУпаковка.СсылкаГпАналитикаГруппа.СсылкаПодразделенияПроизводственныеЦеха
;

ВЫБРАТЬ
	МЕСЯЦ(ГпОтгрузка.Период) КАК НомерМесяца,
	ГпОтгрузка.ГпТранспортнаяУпаковка КАК ТранспортнаяУпаковка,
	ГпОтгрузка.ГпТранспортнаяУпаковка.СсылкаГпАналитикаГруппа.СсылкаПодразделенияПроизводственныеЦеха КАК Цех,
	СУММА(ГпОтгрузка.Вес * &КоэффициентИзмерения) КАК ВесПериод2
ПОМЕСТИТЬ ВТ_Период2
ИЗ
	РегистрНакопления.ГпОтгрузка КАК ГпОтгрузка
ГДЕ
	ГпОтгрузка.Период МЕЖДУ &ДатаНачалаДоп И &ДатаОкончанияДоп
СГРУППИРОВАТЬ ПО
	МЕСЯЦ(ГпОтгрузка.Период),
	ГпОтгрузка.ГпТранспортнаяУпаковка,
	ГпОтгрузка.ГпТранспортнаяУпаковка.СсылкаГпАналитикаГруппа.СсылкаПодразделенияПроизводственныеЦеха
;

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

Важные нюансы реализации

Посмотрим на практические ограничения обоих методов, которые нужно учитывать:

  1. Обработка отсутствующих значений. Если в каком-то месяце отгрузок не было, при использовании полного соединения необходимо обязательно оборачивать числовые поля в функцию ЕСТЬNULL(), иначе вычитание вернет пустое значение вместо разницы.
  2. Производительность. Первый вариант через ОБЪЕДИНИТЬ ВСЕ выполняется СУБД существенно быстрее, так как не требует построения хэш-таблиц для полного соединения по нескольким полям. При анализе миллионов записей регистра рекомендуется отдавать предпочтение первому методу.
  3. Отображение названий месяцев. Чтобы в шапке вместо цифр 1, 2, 3 отображались понятные названия («Январь», «Февраль»), в запросе можно преобразовать номер месяца в строку с помощью конструкции ВЫБОР КОГДА либо настроить форматирование и макет заголовка группировки в СКД.
← На главную