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

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

Сравнительный анализ данных за разные периоды (например, текущий месяц к аналогичному месяцу прошлого года или текущий квартал к предыдущему) — одна из самых частых задач при разработке отчетов в Системе компоновки данных (СКД). Когда базовый запрос отчета уже содержит множество временных таблиц, виртуальных таблиц остатков и оборотов, простое добавление условий может запутать разработчика.

В этой статье мы подробно разберем три основных метода решения этой задачи, исправим типичные ошибки начинающих разработчиков и покажем, как сделать интерфейс выбора периодов максимально удобным для пользователей.

Причина проблемы: почему стандартный подход автора не работал?

Автор темы пытался использовать механизм связи двух наборов данных, но столкнулся с тем, что данные за оба периода выводились одинаковыми либо возникала ошибка «Номенклатура не найдена». Выясним причину этого поведения:

  1. Пересечение параметров: СКД по умолчанию автоматически подставляет глобальные параметры &НачалоПериода и &КонецПериода во все виртуальные таблицы всех наборов данных. В итоге оба запроса выполнялись за один и тот же период.
  2. Ошибка сопоставления полей: Если во втором наборе данных поле связи (например, Номенклатура) не выбрано в секции ВЫБРАТЬ или не отмечено в СКД как доступное поле, связь установить не удастся.
  3. Потеря данных при левом соединении: При прямой связи наборов данных один из них всегда является ведущим. Если во втором периоде продавался товар, которого не было в первом, то при левом соединении этот товар просто исчезнет из отчета.

Рассмотрим подробнее три профессиональных способа решения этой задачи.

---

Метод 1. Объединение запросов (UNION) и вывод в кросс-таблицу

Этот метод считается наиболее надежным и гибким. Вместо связывания разных наборов данных на уровне СКД, мы объединяем данные в один результирующий пакет на уровне СУБД, а затем с помощью возможностей группировки СКД выводим их в колонки.

Рассмотрим по шагам, как это реализовать:

Шаг 1. Модификация текста запроса

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


// ПОДПАКЕТ 1: Данные за первый период
ВЫБРАТЬ
    Продажи.Номенклатура КАК Номенклатура,
    Продажи.Склад КАК Склад,
    Продажи.КоличествоОборот КАК Количество,
    Продажи.СтоимостьОборот КАК Сумма,
    "Период 1" КАК ПериодСравнения
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода1, &КонецПериода1, , ) КАК Продажи

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

// ПОДПАКЕТ 2: Данные за второй период
ВЫБРАТЬ
    Продажи.Номенклатура,
    Продажи.Склад,
    Продажи.КоличествоОборот,
    Продажи.СтоимостьОборот,
    "Период 2"
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода2, &КонецПериода2, , ) КАК Продажи

Шаг 2. Настройка структуры отчета в СКД

Чтобы вывести эти данные красиво, перейдем на вкладку «Настройки» в СКД:

  1. Создадим структуру типа «Таблица» вместо обычной группировки.
  2. В Строки таблицы добавим группировки Склад и Номенклатура.
  3. В Колонки таблицы добавим группировку по нашему новому полю ПериодСравнения.
  4. В Выбранные поля добавим ресурсы Количество и Сумма.

В результате СКД автоматически сформирует кросс-таблицу, где в строках будут товары, а в колонках — выбранные показатели, разделенные по двум периодам.

Шаг 3. Расчет абсолютного отклонения (дельты)

Чтобы посчитать разницу между периодами прямо в кросс-таблице, воспользуемся вкладкой «Ресурсы»:

  1. Создадим новое вычисляемое поле (например, ОтклонениеСуммы) на вкладке «Вычисляемые поля» без указания формулы.
  2. На вкладке «Ресурсы» добавим это поле и в качестве выражения укажем следующую формулу:

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

Эта функция СКД автоматически вычислит разность между значениями текущей колонки («Период 2») и предыдущей («Период 1»). Для реализации подобных вычислений подойдет пример расчета дельты, отклонений и нарастающих итогов в СКД.

---

Метод 2. Связь нескольких наборов данных с использованием ведущего набора

Если запросы слишком сложные или собираются из разных баз/источников, можно использовать связь наборов данных. Чтобы обойти проблему потери данных при левом соединении, мы применим технику «Полного набора» через справочник.

Проанализируем архитектуру этого решения:

  1. НаборДанных1 (Справочник): Простой запрос к справочнику Номенклатура (можно с отбором по остаткам или продажам за оба периода суммарно), который возвращает уникальный список товаров. Этот набор будет ведущим.
  2. НаборДанных2 (Период 1): Запрос по первому периоду с параметрами &НачалоПериода1 и &КонецПериода1.
  3. НаборДанных3 (Период 2): Запрос по второму периоду с параметрами &НачалоПериода2 и &КонецПериода2.

Настройка связей наборов данных:

Перейдем на вкладку «Связи наборов данных» и настроим два соединения:

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

---

Метод 3. Функция `ВычислитьВыражение` для последовательных периодов

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

Рассмотрим пример. Запрос выбирает продажи по месяцам:


ВЫБРАТЬ
    Продажи.Номенклатура КАК Номенклатура,
    Продажи.Период КАК Месяц,
    Продажи.СтоимостьОборот КАК Сумма
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Месяц, ) КАК Продажи

В СКД на вкладке «Ресурсы» мы можем легко рассчитать сумму продаж за прошлый месяц для каждой строки текущего месяца. Для этого добавим ресурс со следующим выражением:

ВычислитьВыражение("Сумма(Сумма)", "Месяц", , "Предыдущая", "Предыдущая")

А для расчета процента прироста к прошлому месяцу используем выражение:


Выбор 
    Когда ВычислитьВыражение("Сумма(Сумма)", "Месяц", , "Предыдущая", "Предыдущая") = 0 Тогда 0 
    Иначе (Сумма(Сумма) - ВычислитьВыражение("Сумма(Сумма)", "Месяц", , "Предыдущая", "Предыдущая")) 
          / ВычислитьВыражение("Сумма(Сумма)", "Месяц", , "Предыдущая", "Предыдущая") * 100 
Конец

Этот метод работает быстрее всего, так как СУБД выполняет только один легкий запрос, а сопоставление периодов берет на себя быстрый процессор компоновки данных 1С.

---

Полезный лайфхак: удобный выбор периодов для пользователя

Если оставить параметры как есть, пользователю на форме отчета придется заполнять 4 разные даты (две даты начала и две даты окончания). Это крайне неудобно и часто приводит к ошибкам ввода. Оптимизируем этот процесс с помощью системного типа данных СтандартныйПериод.

Посмотрим на алгоритм настройки:

  1. Перейдем на вкладку «Параметры» в СКД.
  2. Добавим два новых параметра: Период1 и Период2 с типом данных СтандартныйПериод.
  3. Поставим для них галочку «Включать в пользовательские настройки».
  4. Для системных параметров дат (&НачалоПериода1, &КонецПериода1 и т.д.) установим флажок «Ограничение доступности» (чтобы скрыть их от пользователя).
  5. В колонке «Выражение» для скрытых параметров пропишем формулы связи с пользовательскими периодами:
Имя параметра Выражение (формула расчета)
НачалоПериода1 &Период1.ДатаНачала
КонецПериода1 &Период1.ДатаОкончания
НачалоПериода2 &Период2.ДатаНачала
КонецПериода2 &Период2.ДатаОкончания

Благодаря этой настройке пользователь на форме отчета увидит два привычных интерактивных поля выбора периода (например, «Прошлый месяц» и «Этот месяц»), а система сама автоматически разложит их на конкретные граничные даты и передаст в виртуальные таблицы запроса.

← На главную