Как устранить задвоение сумм в вышестоящих группировках СКД при связи один-ко-многим?

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

При разработке отчетов в системе компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда данные из родительского объекта (например, справочника Договоры или шапки документа) выводятся совместно с детальными записями подчиненных таблиц или документов-регистраторов. В этом случае возникает связь «один-ко-многим» (1:N), из-за которой реквизит шапки дублируется в каждой строке детальных записей выборки.

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

Причина возникновения задвоения сумм

Рассмотрим структуру запроса: при объединении или левом соединении таблицы договоров с движениями регистратора платформа формирует плоскую таблицу. Если по одному договору проведено три документа, в результирующем наборе поле Договор.Стоимость будет повторено трижды с одинаковым числом.

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

Способ 1. Использование функции ВычислитьВыражениеСГруппировкойМассив в ресурсах

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

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

Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(ДоговорЗапланировано)", "Договор"))

Посмотрим на логику работы этой конструкции:

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

Обратите внимание: функция работы с массивами формирует промежуточные коллекции в оперативной памяти. На очень больших отчетах (сотни тысяч записей) такой расчет может замедлять формирование отчета.

Способ 2. Использование нескольких наборов данных и связей СКД

Разберем архитектурно более чистое решение, которое исключает расчет по массивам в памяти и переносит логику на уровень компоновки данных. Для этого разделим плоский запрос на два независимых набора данных-запроса:

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

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

  1. В поле Источник связи укажем НаборДанных1.
  2. В поле Приемник связи укажем НаборДанных2.
  3. В поле Условие связи свяжем поля по Договор.

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

Способ 3. Разделение строк через ОБЪЕДИНИТЬ ВСЕ в одном запросе

Если необходимо сохранить отчет на одном наборе данных-запросе и избежать сложных формул в ресурсах, применим разделение веток запроса с последующим автоматическим сворачиванием в СКД:


ВЫБРАТЬ
    Договоры.Организация КАК Организация,
    Договоры.Ссылка КАК Договор,
    НЕОПРЕДЕЛЕНО КАК Регистратор,
    Договоры.Стоимость КАК СтоимостьДоговора,
    0 КАК СуммаДокумента
ИЗ
    Справочник.ДоговорыКонтрагентов КАК Договоры

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

ВЫБРАТЬ
    Взаиморасчеты.Договор.Организация,
    Взаиморасчеты.Договор,
    Взаиморасчеты.Регистратор,
    0,
    Взаиморасчеты.Сумма
ИЗ
    РегистрНакопления.ВзаиморасчетыСКонтрагентами КАК Взаиморасчеты

При таком формировании выборки поле СтоимостьДоговора присутствует ровно один раз для каждого договора. В строках с документами-регистраторами оно равно нулю, поэтому стандартный ресурс Сумма(СтоимостьДоговора) рассчитывает корректные итоги на всех уровнях группировок без задвоения.

← На главную