Как правильно рассчитать итоги в СКД при дублировании строк из-за соединений в запросе?

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

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

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

Анализ проблемы: почему стандартные ресурсы работают некорректно

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

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

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

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

Вместо стандартного выражения Сумма(Поле), на вкладке Ресурсы для проблемного поля необходимо прописать сложное выражение. Проанализируем пример выражения, который помог автору темы:


Сумма(ВычислитьВыражениеСГруппировкойМассив ("Максимум(СуммаНДСОтчетаКомитенту)", "ПТУ, ОтчетКомитенту"))

Разберем, как работает эта конструкция:

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

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

Решение №2: Использование нескольких наборов данных (Dataset)

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

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

  1. Создаем НаборДанных1, в котором выбираем только основные данные (Контрагент, Отчет комитента, его общая сумма). Здесь строк ровно столько, сколько документов.
  2. Создаем НаборДанных2, в котором выбираем детальные записи (ПТУ, номенклатура, количество).
  3. Переходим на вкладку Связи наборов данных.
  4. Связываем наборы по ключевому полю (например, по ссылке на Отчет комитента или по Контрагенту).

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

Решение №3: Тонкая настройка ролей полей

Иногда проблему можно решить, не прибегая к сложным формулам, а правильно распределив Роли полей на вкладке «Наборы данных».

Выясним, как это работает: Для поля, которое дублируется, можно попробовать настроить роль «Игнорировать значения NULL» или указать его как часть уникального ключа строки. Однако стоит помнить, что роли в СКД в первую очередь влияют на построение иерархии и работу с остатками. Для решения проблемы «Один ко многим» в оборотных показателях роли помогают реже, чем функция ВычислитьВыражениеСГруппировкойМассив.

Обработка пустых значений (NULL) и производительность

При использовании сложных выражений в ресурсах мы должны учитывать два критических фактора:

1. Обработка NULL. Если в данных присутствуют пустые значения, функция Максимум() или Сумма() может вести себя некорректно. Рекомендуем всегда обрабатывать поля в тексте запроса или в вычисляемых полях:

ЕСТЬNULL(СуммаНДСОтчетаКомитенту, 0)

2. Скорость работы. Функция ВычислитьВыражениеСГруппировкойМассив выполняется в памяти сервера приложений 1С. Если ваш отчет выводит сотни тысяч строк, расчет таких ресурсов может занять значительное время. В таких случаях лучше пересмотреть структуру запроса (использовать временные таблицы с предварительной агрегацией) или метод со связями наборов данных.

Практические советы по отладке

Если результат все равно не сходится, выполните следующие действия:

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

← На главную