При разработке отчетов в системе компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда визуальная сумма строк не совпадает с итогом по группировке, а попытка округлить значение прямо в запросе с помощью конструкции ВЫРАЗИТЬ(... КАК ЧИСЛО(15, 2)) приводит к непредсказуемым результатам: например, близкие по значению числа округляются по-разному или отображается один знак после запятой вместо двух. Разберем по шагам, почему это происходит и как правильно настроить расчет данных.
Рассмотрим типичный пример. В отчете выводятся количество и цена, а поле стоимости рассчитывается как их произведение. Предположим, что мы видим следующие строки:
ВЫРАЗИТЬ показывает 2 540,5.На первый взгляд, у чисел абсолютно одинаковая дробная часть (,475), но в одном случае число округлилось вверх до сотых с переходом в десятые, а во втором — до странного значения ,49 вместо ожидаемого ,48. Проверим расчет в консоли запросов:
ВЫБРАТЬ
ВЫРАЗИТЬ(35.113 * 75 КАК ЧИСЛО(15, 2)) КАК Результат1,
ВЫРАЗИТЬ(33.873 * 75 КАК ЧИСЛО(15, 2)) КАК Результат2
Прямой запрос к СУБД возвращает значения 2 633,48 и 2 540,48. Это доказывает, что механизм приведения типов платформы 1С работает предсказуемо, а корень проблемы кроется в структуре входных данных и особенностях отображения чисел.
Выясним причину расхождения: чаще всего операнды (количество или цена) формируются расчетным путем (деление, распределение коэффициентов) либо хранятся в реквизитах с разрядностью выше трех знаков после запятой. Если для поля в СКД задан формат с тремя знаками, пользователь видит число 35,113, тогда как в базе реально хранится, например, 35,1132.
Посмотрим на пример вычислений с полными разрядами:
35,1132 * 75 = 2 633,4900
При усечении или скрытии разрядов форматом пользователю кажется, что программа ошиблась при умножении 35,113 * 75, тогда как запрос честно перемножил и округлил исходные неокругленные операнды.
Результат 2 540,5 вместо 2 540,50 обусловлен тем, что числовой тип данных в 1С сам по себе не хранит незначащие нули справа. Если в результате округления сотые доли обращаются в ноль, платформа по умолчанию отсекает его при стандартном представлении числа. Чтобы сотые доли всегда присутствовали на экране, числовое округление обязательно должно дополняться строковым форматированием.
Проанализируем частую ошибку: попытку решить проблему расхождения итогов исключительно настройкой свойства Формат (параметр ЧДЦ=2) в полях набора данных. Форматирование меняет только визуальное представление ячейки в отчете. СКД при подсчете итоговых сумм агрегирует полные числовые значения из базы данных, из-за чего сумма визуально округленных строк гарантированно разойдется с итоговой строкой группировки.
Разберем по шагам надежные способы устранения проблемы в зависимости от места расчета показателей.
Если данные рассчитываются в наборе данных типа «Запрос», необходимо явно зафиксировать точность каждого множителя перед перемножением либо ограничить разрядность самого результата:
ВЫБРАТЬ
Таблица.Номенклатура КАК Номенклатура,
ВЫРАЗИТЬ(Таблица.Количество КАК ЧИСЛО(15, 3)) КАК Количество,
ВЫРАЗИТЬ(Таблица.Цена КАК ЧИСЛО(15, 2)) КАК Цена,
ВЫРАЗИТЬ(Таблица.Количество * Таблица.Цена КАК ЧИСЛО(15, 2)) КАК Стоимость
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Таблица
Чтобы исключить потерю нулей при выводе, для поля Стоимость на вкладке Наборы данных в колонке Оформление зададим формат:
ЧДЦ=2; ЧРД=,; ЧГ=3,0
Если стоимость рассчитывается средствами компоновщика данных, нельзя использовать синтаксис языка запросов. Напомним, что в выражениях СКД функция Выразить имеет другой синтаксис, а тип данных передается строковым литералом.
Стоимость.Выразить(Количество * Цена, "Число(15, 2)")
Стоимость укажем выражение агрегации:
Сумма(Стоимость)
При таком подходе СКД сначала вычислит и округлит значения в детальных строках, а затем сложит уже округленные числа. В результате суммовой итог полностью совпадет со значениями детальных записей.
Конструкция ВЫРАЗИТЬ на уровне СУБД транслируется в функцию CAST, которая в зависимости от СУБД (PostgreSQL или MS SQL Server) может применять банковское округление (к ближайшему четному). Если бизнес-логика требует строгого арифметического округления (где 0,005 всегда округляется до 0,01 вверх), вызовем функцию общего модуля в СКД.
Создадим в общем серверном модуле (с признаками «Сервер», «Внешнее соединение») экспортную функцию:
Функция ОкруглитьДоСотых(Значение) Экспорт
Возврат Окр(Значение, 2, РежимОкругления.Окр15как20);
КонецФункции
Затем в схеме компоновки данных на вкладке Вычисляемые поля используем вызов функции:
ОбщийМодульСервер.ОкруглитьДоСотых(Количество * Цена)
Это гарантирует одинаковый результат округления независимо от используемой СУБД и обеспечит идеальную сходимость сумм в отчете.