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

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

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

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

Выясним причину: почему суммы задваиваются?

Рассмотрим ситуацию на примере запроса, представленного автором темы. В нем происходит ЛЕВОЕ СОЕДИНЕНИЕ регистра накопления ОплатаСчетовИЗаказов с табличной частью документа ПоступлениеНаСчет.РасшифровкаПлатежа по полю Заказ.


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

Если по одному объекту Заказ в регистре есть одна запись на 10 000 рублей, а в документе оплаты три строки по 3 333 рубля, то результат запроса выдаст три строки. В каждой из этих трех строк поле СуммаЗаказ будет содержать значение 10 000. Когда СКД начнет рассчитывать ресурс Сумма(СуммаЗаказ), она просто сложит эти значения и выдаст 30 000 рублей вместо корректных 10 000. Проанализируем, как этого избежать.

Решение №1: Использование функции ВычислитьВыражениеСГруппировкойМассив

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

Разберем по шагам, как настроить такой ресурс. Вместо стандартного СУММА(СуммаЗаказ) на закладке «Ресурсы» необходимо прописать следующее выражение для поля СуммаЗаказ:

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

Как это работает?

  1. Функция ВычислитьВыражениеСГруппировкойМассив собирает данные во внутренний массив.
  2. Первый параметр "Максимум(СуммаЗаказ)" говорит системе: «Возьми максимальное значение суммы внутри каждой группы». Поскольку внутри одного заказа сумма всегда одинакова, Максимум, Минимум или Среднее вернут одно и то же число — исходную сумму заказа.
  3. Второй параметр "Заказ" определяет контекст группировки. Система понимает, что массив должен состоять из уникальных значений сумм для каждого заказа.
  4. Внешняя функция СУММА(...) складывает элементы полученного массива. Таким образом, в итог попадут только уникальные значения сумм заказов, а дубли, возникшие из-за строк оплат, будут проигнорированы.

Решение №2: Разделение на наборы данных (Dataset Links)

Более «архитектурно правильный» способ в рамках идеологии СКД — это использование двух разных наборов данных. Рассмотрим этот метод подробнее.

Вместо одного сложного запроса с соединением (JOIN), мы создаем два простых запроса:

  1. НаборДанных1: Получает данные только по заказам и их суммам.
  2. НаборДанных2: Получает данные только по оплатам (ссылка на заказ и сумма оплаты).

Затем на закладке «Связи наборов данных» мы устанавливаем связь по полю Заказ. Источником связи будет НаборДанных1, приемником — НаборДанных2.

Преимущества этого метода:

Решение №3: Изменение структуры запроса через ОБЪЕДИНИТЬ ВСЕ

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


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

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

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

При такой структуре в отчете для каждого заказа будет одна строка с заполненной суммой заказа (и пустой оплатой) и несколько строк с суммами оплат (и нулевой суммой заказа). В ресурсах достаточно будет прописать обычное СУММА(СуммаЗаказ) и СУММА(СуммаОплаты). Итоги по группировкам соберутся корректно, так как значения разнесены по разным физическим строкам.

Резюме и рекомендации

Мы проанализировали три основных подхода к решению проблемы задваивания сумм в СКД. Выбор конкретного метода зависит от сложности вашего отчета:

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

← На главную