Почему СКД неправильно считает итоги в иерархических группировках и как это исправить?

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

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

Проблема 1: Особенности работы с числами с плавающей точкой

Самая частая причина расхождения итогов в иерархии — это использование типа данных Double (число с плавающей точкой) при расчетах. В компьютерной памяти такие числа хранятся с определенной погрешностью. Когда система суммирует тысячи строк, эти микроскопические доли накапливаются, и в итоге родительская ветка иерархии показывает значение, отличающееся от суммы видимых дочерних элементов на 0.01 или даже больше.

Для решения этой проблемы мы должны гарантировать, что данные попадают в механизм агрегации СКД уже в округленном виде. Рассмотрим, как это сделать правильно в тексте запроса. Недостаточно просто задать формат в оформлении поля, нужно использовать функцию ВЫРАЗИТЬ.

Проанализируем пример кода в запросе:


ВЫБРАТЬ
    Продажи.Номенклатура КАК Номенклатура,
    ВЫРАЗИТЬ(Продажи.СуммаОборот КАК ЧИСЛО(15, 2)) КАК Сумма
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК Продажи

Именно использование ВЫРАЗИТЬ(... КАК ЧИСЛО(15, 2)) отсекает «хвосты» после второго знака еще на этапе получения данных из базы. В этом случае иерархические итоги будут рассчитываться на основе уже чистых значений, и погрешность исчезнет.

Проблема 2: Дублирование данных при левых соединениях

Вторая по популярности причина «раздутых» итогов в иерархии — некорректные соединения (Joins) в наборах данных. Если к основной таблице (например, остаткам) присоединяется таблица с дополнительными реквизитами, где одному объекту соответствует несколько записей, суммы начнут множиться.

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

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

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

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

Проблема 3: Роли полей и настройка иерархии

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

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

Проблема 4: Отличие «Иерархии» от «Только иерархии»

Часто путаница возникает из-за визуального представления данных. Разберем разницу:

  1. Иерархия — выводит и саму папку (группу), и элементы внутри неё. Если ресурс есть и у папки, и у элементов, стандартная функция Сумма() сложит их все.
  2. Только иерархия — выводит структуру дерева без детальных записей, которые не являются узлами.

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

Проблема 5: Влияние отборов на итоговые значения

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

Если нам нужно видеть полный итог по иерархии, несмотря на отборы в детальных записях, следует использовать параметры связи наборов данных или специфические настройки ресурсов с использованием ВычислитьВыражение и ключевого слова ОбщийИтог.

Подведем итоги

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

  1. Всегда округляем денежные поля в запросе через ВЫРАЗИТЬ.
  2. Проверяем запросы на наличие левых соединений, которые могут дублировать строки.
  3. Правильно настраиваем Роли полей (Ключ и Родитель).
  4. Используем ВычислитьВыражениеСГруппировкойМассив, если логика суммирования сложнее, чем простое сложение всех строк.

Соблюдение этих шагов позволит избежать большинства проблем с итоговыми суммами и сделает ваши отчеты надежными и точными.

← На главную