При разработке специфических систем учета в 1С (например, при работе с высокоточными величинами или криптовалютами) разработчики часто сталкиваются с необходимостью хранить дробные числа с точностью до 10 знаков после запятой. Однако при создании ресурса регистра накопления с типом Число(20,10) происходит неприятное поведение: движения по регистру записываются корректно, а при запросе остатков платформа возвращает ноль в последних разрядах (например, вместо 0,0000000001 выводится 0,0000000000).
В этой статье мы подробно разберем причину такого поведения СУБД и платформы 1С, а также рассмотрим несколько способов решения этой задачи.
Рассмотрим, что происходит на уровне системы управления базами данных (СУБД MS SQL Server или PostgreSQL) при проведении документа и расчете остатков по регистру накопления:
DECIMAL в СУБД и в платформе 1С составляет 38 знаков.SUM.Число(20,10) с учетом автоматического запаса СУБД под суммирование итоговая разрядность превышает лимит в 38 знаков. В результате СУБД сбрасывает точность дробной части с 10 до 8 знаков, из-за чего сверхмалые значения (такие как 0,0000000001) теряются и обнуляются при пересчете таблиц итогов.Самый простой и эффективный способ исправить проблему без переписывания кода — уменьшить разрядность целой части числа в свойствах ресурса регистра накопления.
Проанализируем пример: если задать типом ресурса Число(14,10) вместо Число(20,10), то суммарная длина числа составит 24 знака. Это оставляет СУБД необходимый запас разрядности при выполнении операции SUM в пределах допустимого лимита (38 знаков).
Разберем по шагам действие разработчика:
Важное замечание: при увеличении целой части до Число(15,10) или Число(16,10) десятый знак после запятой снова начнет срезаться при проведении документов и обновлении итогов, поэтому значение длины 14 является оптимальным лимитом для точности 10 знаков.
Если для бизнес-логики одновременно требуются и большие значения целой части, и высокая точность дробной, стандартное ограничение типов СУБД можно обойти архитектурно. Для этого используется учет в целых числах с определенным множителем.
Рассмотрим принцип работы этого метода:
Число(38,0) или Число(20,0) без дробной части.Посмотрим на пример вычисления повышенной точности в запросе 1С:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(13.1 / 13 КАК ЧИСЛО(27, 25)) КАК Точность";
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Сообщить(Строка(Выборка.Точность));
КонецЕсли;
Если данные запрашиваются из таблицы оборотов или непосредственно из таблицы документов (без использования таблицы итогов остатков), усечения точности можно избежать явным приведением типов прямо в тексте запроса.
Проанализируем конструкцию запроса с явным управлением разрядностью:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(СУММА(Регистр.Количество) КАК ЧИСЛО(24, 10)) КАК КоличествоОстаток
|ИЗ
| РегистрНакопления.МойРегистр КАК Регистр";
Использование ВЫРАЗИТЬ с явным указанием длины 24 и точности 10 заставляет СУБД сохранять требуемый масштаб при агрегации данных.
Даже если данные в базе записаны корректно, стандартные механизмы платформы (например, Система компоновки данных или Универсальный отчет) могут округлять выводимые числа при отображении на форме.
Чтобы убедиться, что отчёт отображает все 10 знаков после запятой:
ЧДЦ=10; ЧН=0 (где ЧДЦ — число знаков дробной части).