Почему расчеты в СКД могут давать неверный результат при умножении и как это исправить?

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

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

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

Причина 1: Неправильная логика расчета ресурсов

Разберем типичную ошибку. Допустим, у нас есть поле Вес и вычисляемое поле ОплатаЗаВес, которое рассчитывается как Вес * 0.09. Если в настройках ресурсов мы просто укажем Сумма(ОплатаЗаВес), система может повести себя не так, как мы ожидаем.

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

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

Сумма(Вес) * 0.09

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

Причина 2: Дублирование строк при левом соединении

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

Рассмотрим пример запроса, где к документу МаршрутноеЗадание присоединяются товары из реализации:


ВЫБРАТЬ
    МаршрутноеЗаданиеДокументыРеализации.Ссылка.ВесГруза КАК Вес,
    МаршрутноеЗаданиеДокументыРеализации.Ссылка.Водитель КАК Водитель,
    ВЫРАЗИТЬ(МаршрутноеЗаданиеДокументыРеализации.Ссылка.ВесГруза * 0.09 КАК ЧИСЛО(15, 2)) КАК ОплатаДня
ИЗ
    Документ.МаршрутноеЗадание.ДокументыРеализации КАК МаршрутноеЗаданиеДокументыРеализации
ЛЕВОЕ СОЕДИНЕНИЕ 
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары 
    ПО МаршрутноеЗаданиеДокументыРеализации.Реализация = РеализацияТоваровУслугТовары.Ссылка

В чем здесь ловушка? Если в документе реализации 10 товаров, то ЛЕВОЕ СОЕДИНЕНИЕ создаст 10 строк для одного и того же ВесГруза. Когда СКД начнет рассчитывать ресурс Сумма(Вес), она сложит этот вес 10 раз. В итоге в отчете мы увидим цифру, в десять раз превышающую реальную.

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

Причина 3: Особенности функции ВЫРАЗИТЬ и округление

Часто программисты используют ВЫРАЗИТЬ(... КАК ЧИСЛО) в самом запросе. Выясним, как это влияет на точность. Если не указать разрядность (например, 15 и 2), система может отсекать дробную часть или округлять её по правилам СУБД, которые иногда отличаются от правил 1С. Для финансовых расчетов, таких как оплата за вес, это критично.

Посмотрим на пример правильного приведения типов в запросе:

ВЫРАЗИТЬ(МаршрутноеЗадание.ВесГруза * 0.09 КАК ЧИСЛО(15, 2))

Это жестко задает точность до двух знаков после запятой еще на этапе выполнения запроса в SQL. Однако помните, что если вы считаете это в запросе, а потом в СКД используете ресурс Сумма, то вы суммируете уже округленные до копеек значения. Иногда для точности лучше суммировать исходный вес в ресурсах с большой точностью, и только итоговый результат умножать на 0.09.

Алгоритм настройки корректного расчета в СКД

Рассмотрим пошагово, как правильно настроить отчет, чтобы избежать проблем с умножением:

  1. Проверьте набор данных (запрос): Убедитесь, что из-за JOIN строки не дублируются. Если дублирование неизбежно, используйте СГРУППИРОВАТЬ ПО или временные таблицы.
  2. Настройте вычисляемое поле: На вкладке «Вычисляемые поля» добавьте поле ОплатаЗаВес. В выражении напишите Вес * 0.09. Это поле будет рассчитываться для каждой детальной записи.
  3. Настройте ресурсы: Перейдите на вкладку «Ресурсы».
    • Для поля Вес укажите выражение Сумма(Вес).
    • Для поля ОплатаЗаВес вместо Сумма(ОплатаЗаВес) напишите Сумма(Вес) * 0.09.
  4. Обработка пустых значений: Чтобы избежать ошибок при умножении, если вес не заполнен, используйте функцию ЕСТЬNULL. В запросе это выглядит так: ЕСТЬNULL(ВесГруза, 0). В вычисляемом поле СКД можно использовать аналогичную проверку.

Оптимизация производительности

Разберем замечание о том, что после переноса формул в ресурсы отчет может «грузиться дольше». Это происходит потому, что расчеты переносятся с уровня SQL-сервера на уровень сервера приложений 1С. Когда записей тысячи, разница незаметна, но на миллионах строк это может стать проблемой.

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

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

← На главную