Как правильно округлять числа в запросах 1С и системе компоновки данных (СКД)?

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

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

Разбор ошибки арифметического переполнения в запросе

Рассмотрим ситуацию: разработчик пытается рассчитать цену за единицу товара прямо в запросе, используя стандартную функцию ВЫРАЗИТЬ. Код выглядит следующим образом:


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

При выполнении такого запроса система выдает критическую ошибку: «Microsoft SQL Server Native Client 11.0: Ошибка арифметического переполнения при преобразовании numeric к типу данных numeric. HRESULT=80040E57». Проанализируем причину её возникновения.

Ошибка кроется в понимании параметров типа ЧИСЛО(L, P) внутри функции ВЫРАЗИТЬ:

  1. L (Length) — это общая длина числа, включая все знаки до запятой и все знаки после запятой.
  2. P (Precision/Scale) — это количество знаков после запятой.

Таким образом, конструкция ЧИСЛО(5, 2) означает, что под всё число отводится 5 позиций, из которых 2 — десятичные. Это значит, что на целую часть остается всего 3 знака (5 минус 2). Максимальное число, которое может поместиться в такую структуру — 999,99. Если в результате деления суммы на количество получится число 1000 и более, SQL Server не сможет записать его в отведенную память и вернет ошибку переполнения.

Для решения этой проблемы необходимо всегда задавать разрядность «с запасом». В типовых конфигурациях 1С для финансовых показателей чаще всего используется ЧИСЛО(15, 2) или даже ЧИСЛО(31, 2), что позволяет избежать падения запроса при работе с большими суммами.

Округление vs Оформление: в чем принципиальная разница?

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

1. Функция ВЫРАЗИТЬ в запросе.

Эта функция работает на уровне СУБД и выполняет физическое преобразование типа. Она делает математическое округление. Это означает, что само значение числа в памяти компьютера меняется. Если вы потом будете использовать это поле в итогах СКД (например, суммировать округленную цену), результат будет рассчитан именно на основе округленных копеек.

2. Настройка «Формат» в СКД.

Если мы зайдем в настройки набора данных или в настройки оформления поля в СКД и установим формат «ЧДЦ=2» (Число Десятичных Цифр = 2), значение числа не изменится. Программа просто «спрячет» лишние знаки от пользователя при выводе в таблицу. В памяти же останется число с бесконечным количеством знаков после запятой (например, 53,103469...).

Почему это важно? Если вы выводите отчет, где много строк, и в каждой строке цена только «оформлена» через формат, то итоговая сумма внизу отчета может не совпасть с результатом ручного сложения видимых чисел на калькуляторе. Возникает эффект «плывущих копеек». Поэтому, если расчеты должны быть точными с точки зрения бухгалтерии, округление нужно делать через ВЫРАЗИТЬ в запросе или через функции в вычисляемых полях.

Округление в вычисляемых полях СКД

Если логика отчета позволяет производить расчеты после получения данных из БД, удобнее использовать вкладку «Вычисляемые поля» в СКД. Там нам доступен программный язык 1С, который богаче на математические функции, чем язык запросов.

Рассмотрим пример использования функции Окр() в выражении вычисляемого поля:

Окр(Сумма / Количество, 2, РежимОкругления.Окр15как20)

Преимущество этого метода в том, что мы можем явно управлять режимом округления (например, всегда округлять 1.5 до 2.0 или использовать банковское округление). В языке запросов через ВЫРАЗИТЬ доступно только стандартное математическое округление, принятое в SQL Server.

Как получить только целую часть числа (отсечение)

Иногда стоит задача не округлить число, а просто «отрезать» дробную часть. Например, из 53.9 получить 53. В языке запросов 1С нет функции FLOOR или ЦЕЛ. Как быть?

Существует несколько подходов:

  1. Использование ВЫРАЗИТЬ с нулевой точностью: ВЫРАЗИТЬ(МоеЧисло КАК ЧИСЛО(15, 0)). Но помните, что это округление! 53.9 превратится в 54.
  2. Хитрый расчет в запросе: Для положительных чисел можно использовать конструкцию ВЫРАЗИТЬ(МоеЧисло - 0.5 КАК ЧИСЛО(15, 0)). Это заставит стандартное округление работать как отсечение целой части для большинства случаев.
  3. Вычисляемое поле СКД: Самый надежный и понятный способ. Используйте функцию Цел(Цена) во вкладке «Вычисляемые поля».

Безопасность расчетов: Деление на ноль и NULL

Проанализируем еще одну проблему, которая часто идет рука об руку с округлением в запросах. Если Продажи.Количество окажется равным нулю, запрос завершится аварийно. Чтобы этого избежать, всегда оборачивайте расчеты в конструкцию ВЫБОР:


ВЫБОР 
    КОГДА Продажи.Количество = 0 ТОГДА 0 
    ИНАЧЕ ВЫРАЗИТЬ(Продажи.Сумма / Продажи.Количество КАК ЧИСЛО(15, 2)) 
КОНЕЦ КАК Цена

Также не забывайте о значениях NULL, которые могут появиться при левых соединениях. Функция ВЫРАЗИТЬ(NULL КАК ЧИСЛО) вернет NULL, что может привести к ошибкам в дальнейших арифметических операциях. Используйте ЕСТЬNULL(), чтобы гарантировать наличие числового значения:


ВЫРАЗИТЬ(ЕСТЬNULL(Продажи.Сумма, 0) / ЕСТЬNULL(Продажи.Количество, 1) КАК ЧИСЛО(15, 2))

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

Для корректного округления в 1С придерживайтесь следующих правил:

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

← На главную