При написании запросов в платформе «1С:Предприятие» разработчики часто сталкиваются с ограничениями встроенного языка запросов по сравнению с полноценным SQL или языками высокого уровня (такими как Java или C#). Одной из таких проблем является отсутствие стандартной функции округления числа до ближайшего большего целого (вверх), которая в других языках представлена как Math.ceil() или CEILING().
В этой статье мы подробно разберем, как решить эту задачу в запросе 1С. Мы рассмотрим современный и наиболее надежный способ для актуальных версий платформ, а также классические обходные пути, которые пригодятся, если вы работаете на старых релизах.
Начиная с версии платформы 8.3.20, в язык запросов 1С были добавлены встроенные математические функции, включая ЦЕЛ() (получение целой части числа путем отсечения дроби) и ОКР() (округление по математическим правилам).
Благодаря функции ЦЕЛ(), больше не нужно использовать неточные дробные прибавки. Мы можем реализовать полноценный и математически точный аналог Math.ceil() для любых чисел (положительных, отрицательных и целых) с помощью простого ветвления:
ВЫБРАТЬ
ВЫБОР
КОГДА ЦЕЛ(Таблица.ИсходноеЧисло) = Таблица.ИсходноеЧисло
ТОГДА Таблица.ИсходноеЧисло
КОГДА Таблица.ИсходноеЧисло > 0
ТОГДА ЦЕЛ(Таблица.ИсходноеЧисло) + 1
ИНАЧЕ ЦЕЛ(Таблица.ИсходноеЧисло)
КОНЕЦ КАК РезультатОкругленияВверх
ИЗ
РегистрСведений.НашиДанные КАК Таблица
Проанализируем, как работает этот алгоритм:
5.0 или -3.0), условие равенства выполняется, и запрос возвращает число без изменений.5.1), функция ЦЕЛ() возвращает 5. Так как число больше нуля, мы прибавляем единицу и получаем верный результат: 6.-3.1), функция ЦЕЛ() просто отсекает дробную часть, возвращая -3. Математически число -3 больше, чем -3.1, поэтому для отрицательного диапазона это и есть округление вверх.Если вы работаете на платформе ниже версии 8.3.20, функции ЦЕЛ() в запросах у вас нет. В этом случае единственным штатным инструментом округления остается конструкция ВЫРАЗИТЬ(... КАК ЧИСЛО). Нам придется имитировать логику сравнения целой части с исходным числом.
Рассмотрим следующий рабочий шаблон запроса:
ВЫБРАТЬ
ВЫБОР
КОГДА ВЫРАЗИТЬ(Таблица.ИсходноеЧисло КАК ЧИСЛО(15, 0)) = Таблица.ИсходноеЧисло
ТОГДА Таблица.ИсходноеЧисло
ИНАЧЕ ВЫРАЗИТЬ(Таблица.ИсходноеЧисло + 0.5 КАК ЧИСЛО(15, 0))
КОНЕЦ КАК Ceil
ИЗ
РегистрСведений.НашиДанные КАК Таблица
Разберем логику работы этого выражения по шагам:
2), то ВЫРАЗИТЬ(2 КАК ЧИСЛО(15,0)) вернет 2. Условие 2 = 2 сработает, и вернется исходная двойка.2.1), проверка на равенство вернет ложь. Тогда выполнится ветка ИНАЧЕ: к 2.1 прибавится 0.5, получится 2.6. Конструкция ВЫРАЗИТЬ(2.6 КАК ЧИСЛО(15,0)) округлит это число по математическим правилам до 3.2.9, в ветке ИНАЧЕ мы получим 2.9 + 0.5 = 3.4, что при округлении также даст 3.Иногда разработчики хотят избежать громоздких конструкций ВЫБОР...КОНЕЦ и стремятся написать максимально короткий код. Для этого можно прибавить к числу константу, чуть меньшую 0.5 (например, 0.4999999999):
ВЫБРАТЬ
ВЫРАЗИТЬ(Таблица.ИсходноеЧисло + 0.4999999999 КАК ЧИСЛО(15, 0)) КАК Ceil
ИЗ
РегистрСведений.НашиДанные КАК Таблица
Важное предупреждение: этот способ выглядит самым простым, однако он имеет скрытые недостатки:
ВЫРАЗИТЬ выполняется непосредственно на стороне СУБД (MS SQL, PostgreSQL и др.). Разные СУБД могут по-разному обрабатывать числа с большим количеством знаков после запятой, что иногда приводит к потере точности или ошибкам округления.0.00000000001), этот алгоритм может вернуть неверный результат из-за лимитов разрядности.Если вам не обязательно производить округление непосредственно внутри самого запроса (например, поле не участвует в группировках, связях или условиях компоновки), рассмотрите следующие альтернативы:
Цел() или Окр(). Это существенно снизит нагрузку на базу данных и упростит чтение кода.