Как в СКД вывести данные с разными отборами и рассчитать средние значения в одном отчете?

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

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

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

Решение 1: Использование нескольких наборов данных

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

Разберем по шагам:

  1. Откройте схему компоновки данных и перейдите на вкладку "Наборы данных".
  2. Создайте первый набор данных типа "Запрос", назовем его ДанныеСОтбором1. В тексте запроса получите необходимые поля из регистра и примените первый набор жестких отборов в условии ГДЕ. Сгруппируйте данные по месяцам.
  3. 
    // Примерный текст запроса для НабораДанных1
    ВЫБРАТЬ
        НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ) КАК Месяц,
        СУММА(Продажи.Сумма) КАК СуммаПродаж
    ИЗ
        РегистрНакопления.Продажи КАК Продажи
    ГДЕ
        Продажи.Номенклатура.ВидНоменклатуры = &ВидНоменклатуры1
        И Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода
    СГРУППИРОВАТЬ ПО
        НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ)
    
  4. Аналогично создайте второй набор данных ДанныеСОтбором2, но в условии ГДЕ используйте уже второй набор отборов.
  5. 
    // Примерный текст запроса для НабораДанных2
    ВЫБРАТЬ
        НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ) КАК Месяц,
        СУММА(Продажи.Сумма) КАК СуммаПродаж
    ИЗ
        РегистрНакопления.Продажи КАК Продажи
    ГДЕ
        Продажи.Контрагент.Регион = &Регион2
        И Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода
    СГРУППИРОВАТЬ ПО
        НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ)
    
  6. Теперь необходимо связать эти наборы. Перейдите на вкладку "Связи наборов данных".
  7. Создайте новую связь. Укажите один набор как Источник, другой — как Приемник. В качестве условия связи выберите общее поле, в нашем случае это Месяц. Выражение источника: Месяц, Выражение приемника: Месяц.

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

Преимущества:

Решение 2: Вычисляемые поля и условные выражения

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

Рассмотрим два варианта реализации этого подхода.

Вариант А: Разделение в вычисляемых полях СКД

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

  1. Создайте один набор данных "Запрос", который получает все данные, потенциально подпадающие под оба набора отборов. В запросе не должно быть жестких, взаимоисключающих условий.
  2. Перейдите на вкладку "Вычисляемые поля".
  3. Создайте новое поле, например, СуммаПоОтбору1. В колонке "Выражение" напишите формулу с использованием функции языка выражений СКД Выбор().
  4. 
    Выбор
        Когда Номенклатура.ВидНоменклатуры = &ВидНоменклатуры1
        Тогда Сумма
        Иначе 0
    Конец
    
  5. Создайте второе вычисляемое поле СуммаПоОтбору2 с другим условием.
  6. 
    Выбор
        Когда Контрагент.Регион = &Регион2
        Тогда Сумма
        Иначе 0
    Конец
    
  7. Теперь на вкладке "Ресурсы" укажите, что для полей СуммаПоОтбору1 и СуммаПоОтбору2 нужно рассчитывать Сумму().

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

Вариант Б: Разделение в тексте запроса

Можно добавить поле-признак прямо в запрос с помощью конструкции ВЫБОР КОГДА.


ВЫБРАТЬ
    Продажи.Период,
    Продажи.Сумма,
    ВЫБОР
        КОГДА Продажи.Номенклатура.ВидНоменклатуры = &ВидНоменклатуры1
            ТОГДА "Группа отбора 1"
        КОГДА Продажи.Контрагент.Регион = &Регион2
            ТОГДА "Группа отбора 2"
        ИНАЧЕ "Прочее"
    КОНЕЦ КАК ГруппаОтбора
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    // Общие отборы, не взаимоисключающие
    Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода

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

Решение 3: Расчет скользящего среднего

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

Самый надежный способ — рассчитать эти показатели на уровне запроса.

Если ваша СУБД (например, MS SQL Server или PostgreSQL) поддерживает оконные функции, это наиболее производительный и элегантный вариант.


// Пример для СУБД с поддержкой оконных функций
ВЫБРАТЬ
    Данные.Месяц,
    Данные.СуммаПродаж,
    AVG(Данные.СуммаПродаж) OVER (ORDER BY Данные.Месяц ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) КАК СреднееЗа3Месяца,
    AVG(Данные.СуммаПродаж) OVER (ORDER BY Данные.Месяц ROWS BETWEEN 5 PRECEDING AND CURRENT ROW) КАК СреднееЗа6Месяцев
ИЗ
    (ВЫБРАТЬ
        НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ) КАК Месяц,
        СУММА(Продажи.Сумма) КАК СуммаПродаж
    ИЗ
        РегистрНакопления.Продажи КАК Продажи
    // ...Условия отбора...
    СГРУППИРОВАТЬ ПО
        НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ)
    ) КАК Данные

Если оконные функции недоступны, можно использовать соединение таблицы с самой собой (self-join), но этот способ сложнее в написании и может быть менее производительным.

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

Итог и рекомендации

Для решения исходной задачи автора темы оптимальным будет комбинированный подход:

  1. Создайте два набора данных (ДанныеСОтбором1 и ДанныеСОтбором2), как описано в Решении 1. Это обеспечит логическое разделение данных.
  2. В тексте запроса для каждого из этих наборов данных сразу рассчитайте скользящие средние (за 3 и 6 месяцев) с помощью оконных функций, как показано в Решении 3.
  3. Свяжите эти два набора данных по полю Месяц.
  4. В настройках отчета на вкладке "Структура" создайте две отдельные группировки типа "Таблица".
    • В первую таблицу выведите поля из набора ДанныеСОтбором1 (Месяц, СуммаПродаж, СреднееЗа3Месяца и т.д.).
    • Во вторую таблицу, расположенную ниже, выведите поля из набора ДанныеСОтбором2.

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

← На главную