Как правильно суммировать реквизиты шапки документа в СКД, если данные «размножаются» из-за табличных частей?

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

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

Причина возникновения проблемы «размножения» данных

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

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

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


Сумма(ВЫЧИСЛИТЬВыражениесгруппировкоймассив("Максимум(ЗаказПокупателя.КолВоОшибок)", "ЗаказПокупателя"))

Разберем это выражение по шагам:

  1. Функция ВЫЧИСЛИТЬВыражениесгруппировкоймассив создает массив значений, группируя их по указанному полю (в нашем случае — по ссылке на документ ЗаказПокупателя).
  2. Внутри каждой группы (то есть внутри каждого конкретного заказа) мы берем Максимум(ЗаказПокупателя.КолВоОшибок). Поскольку во всех строках одного заказа это значение одинаковое (5), максимум вернет именно 5.
  3. Система формирует массив, где для каждого заказа будет ровно по одному числу.
  4. Внешняя функция Сумма складывает элементы этого массива, получая корректный итог за день или по всему отчету.

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

Решение 2: Настройка ролей полей в наборе данных

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

  1. Перейдем в колонку Роль для нужного поля.
  2. В открывшемся окне установим флаг Игнорировать дублирующие значения.
  3. В поле Выражение для роли укажем ссылку на документ (например, ЗаказПокупателя).

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

Решение 3: Разделение наборов данных

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

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

Работа с NULL в вычисляемых полях и ресурсах

В процессе настройки часто возникают вопросы о том, почему в итогах отображается 0 или пустое значение. Выясним причину, связанную с NULL. В языке запросов 1С любая арифметическая операция с NULL дает NULL (например, 10 + NULL = NULL). Однако в СКД агрегатные функции ведут себя иначе:

  1. Функция Сумма(Поле) в ресурсах автоматически игнорирует NULL. Если в выборке есть значения 5, 10 и NULL, итоговая сумма будет 15.
  2. Если же вы создаете вычисляемое поле на вкладке «Вычисляемые поля» и используете формулу вида ПолеА + ПолеБ, то при наличии NULL в любом из полей результат будет пустым.

Поэтому в вычисляемых полях рекомендуется всегда использовать конструкцию ЕСТЬNULL(Поле, 0). В выражениях ресурсов (на вкладке «Ресурсы») это обычно избыточно, но не будет лишним для страховки.

Расчет итоговых показателей (доли и проценты)

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

Сумма(КолВоОшибок) / ВычислитьВыражение("Сумма(КолВоОшибок)", "ОбщиеИтоги")

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

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

← На главную