Округление в запросах и отчётах 1С: от ВЫРАЗИТЬ до Окр()
Содержание
Внутри запроса округляет не функция Окр(), а оператор ВЫРАЗИТЬ: запись ВЫРАЗИТЬ(Сумма КАК ЧИСЛО(15, 2)) приводит число к двум знакам после запятой с арифметическим округлением. Привычная Окр(Сумма, 2) в чистом языке запросов недоступна — она работает в выражениях системы компоновки данных (СКД) и во встроенном языке.
Это сбивает с толку: код в модуле считает Окр(), а в консоли запросов её нет, зато есть ВЫРАЗИТЬ. Ниже — где какой инструмент применять, как округлять вверх, вниз, до копеек и до сотен, что делать с NULL и делением на ноль, и почему сумма округлённых строк в отчёте иногда не сходится с округлённым итогом.
ВЫРАЗИТЬ КАК ЧИСЛО — основной способ округлить прямо в запросе
В языке запросов 1С 8.3 нет отдельной функции округления. Её роль играет приведение типа через ВЫРАЗИТЬ. Указываете целевую точность — платформа округляет значение под неё.
ВЫБРАТЬ
Продажи.Контрагент КАК Контрагент,
ВЫРАЗИТЬ(Продажи.Сумма КАК ЧИСЛО(15, 2)) КАК СуммаОкругл
ИЗ
РегистрНакопления.Продажи.Обороты КАК Продажи
Числа в скобках читаются так: первое — общая разрядность (сколько всего значащих цифр), второе — число знаков после запятой. ЧИСЛО(15, 2) держит до 13 знаков в целой части и 2 в дробной.
Чтобы округлить до целых рублей, дробную часть обнуляют:
ВЫРАЗИТЬ(Продажи.Сумма КАК ЧИСЛО(15, 0))
💡 ВЫРАЗИТЬ округляет арифметически: 196,666 превращается в 196,67, а 196,664 — в 196,66. Отбрасывания дробной части здесь нет, это именно округление к ближайшему.
Поведение ровно на границе 0,5 в файловой и в клиент-серверной базе может немного различаться — округление на стороне СУБД зависит от самой СУБД. Там, где это деньги и расхождение в копейку критично, задавайте правило явно (через ВЫБОР или Окр в отчёте), а не полагайтесь на тип по умолчанию.
Окр() и Цел(): настоящие функции округления в СКД и коде
Полноценные функции округления живут во встроенном языке и в выражениях СКД — в вычисляемых полях, ресурсах и пользовательских полях отчёта:
Окр(Число, Разрядность)— округляет до указанного числа знаков.Окр(196.666, 2)даёт196.67.Цел(Число)— возвращает целую часть, отбрасывая дробь:Цел(196.99)=196.
У Окр есть третий параметр — режим округления. Он управляет тем, куда идёт ровно половина: по умолчанию 0,5 округляется в бо́льшую сторону по модулю (2,5 → 3), а другой режим эту половину отбрасывает. Точные коды режима удобнее сверить в синтакс-помощнике — если выбор режима влияет на деньги, не угадывайте его, а проверьте на контрольном примере.
Не пытайтесь вызвать Окр() или Цел() внутри ВЫБРАТЬ … ИЗ — платформа выдаст ошибку синтаксического разбора запроса. Эти функции доступны только там, где выражение считает не СУБД, а движок 1С: в модулях и в компоновке данных.
Практический вывод простой: округляете значение, которое выбирается из базы, — используйте ВЫРАЗИТЬ в тексте запроса. Округляете итог или вычисляемый показатель в отчёте — используйте Окр в выражении ресурса.
Чтобы не путаться, где какой инструмент разрешён и что именно он делает:
| Способ | Где работает | Что делает | Когда брать |
|---|---|---|---|
ВЫРАЗИТЬ(X КАК ЧИСЛО(15, 2)) | текст запроса (ВЫБРАТЬ … ИЗ) | арифметическое округление до заданной точности | округление данных прямо в выборке |
Окр(X, 2) | СКД, встроенный язык | округление до N знаков, с режимом для половины | итоги и показатели отчёта |
Цел(X) | СКД, встроенный язык | отбрасывает дробную часть (вниз) | строго вниз, floor |
-Цел(-X) | СКД, встроенный язык | округление к большему целому (вверх) | строго вверх, ceil |
| деление и умножение | текст запроса | округление до десятков, сотен, шага | укрупнение до 10, 100, 0,1 |
Строки Окр и Цел в столбце «текст запроса» намеренно пусты: внутри ВЫБРАТЬ этих функций нет, и попытка их вызвать обрывает разбор запроса ещё до выполнения.
Округление вверх, вниз и до десятков или сотен
Арифметическое округление покрывает не все задачи. Иногда нужно строго вниз (отбросить дробь) или строго вверх (нарастить до целого).
- Вниз, к меньшему целому. Для положительных чисел это
Цел(Число)в СКД или коде.Цел(10.9)=10. - Вверх, к большему целому. Приём
-Цел(-Число): минус разворачивает знак,Целотрезает дробь, второй минус возвращает знак.-Цел(-10.1)=11. - В чистом запросе строгого «только вниз/только вверх» штатно нет. Если floor или ceil нужны в наборе данных, выносите расчёт в СКД или в постобработку результата.
Цел отбрасывает дробь в сторону нуля, а не к меньшему числу. Для положительных это совпадает с округлением вниз, а вот Цел(-10.9) вернёт -10, а не -11. Если в данных бывают минусы (корректировки, сторно, возвраты), проверяйте знак числа отдельно.
Округление до десятков, сотен и тысяч делают через деление и обратное умножение — отрицательной разрядности у ЧИСЛО не бывает:
// до сотен
ВЫРАЗИТЬ(Продажи.Сумма / 100 КАК ЧИСЛО(15, 0)) * 100
// до десятков
ВЫРАЗИТЬ(Продажи.Сумма / 10 КАК ЧИСЛО(15, 0)) * 10
Логика та же, что в школьной математике: уменьшили масштаб, округлили до целого, вернули масштаб. Для округления до 10 копеек делите на 0,1:
ВЫРАЗИТЬ(Продажи.Сумма / 0.1 КАК ЧИСЛО(15, 0)) * 0.1
Условное округление через ВЫБОР КОГДА
Когда правило округления зависит от значения, помогает оператор ВЫБОР. Типичный случай — разная точность для крупных и мелких сумм: крупные показываем до рублей, мелкие — до копеек.
ВЫБОР
КОГДА Продажи.Сумма >= 100000
ТОГДА ВЫРАЗИТЬ(Продажи.Сумма КАК ЧИСЛО(15, 0))
ИНАЧЕ ВЫРАЗИТЬ(Продажи.Сумма КАК ЧИСЛО(15, 2))
КОНЕЦ
ВЫБОР незаменим и там, где округлять нужно только часть строк — например, обнулять отрицательные остатки вместо их округления:
ВЫБОР
КОГДА Остатки.Сумма > 0
ТОГДА ВЫРАЗИТЬ(Остатки.Сумма КАК ЧИСЛО(15, 2))
ИНАЧЕ 0
КОНЕЦ
Сложные схемы — банковское округление «к чётному», округление цены до психологических 0,99 — одним выражением запроса не описываются. Такую логику выносят во встроенный язык или в обработку результата: там доступны циклы и полный набор функций.
NULL и деление на ноль: чтобы округление не превратилось в пустоту
Главная ловушка при округлении в запросе — NULL. Любая арифметика с NULL даёт NULL, и ВЫРАЗИТЬ(NULL КАК ЧИСЛО(15, 2)) тоже вернёт NULL. Одно пустое поле в соединении — и округлённая сумма по строке «проваливается».
Оборачивайте потенциально пустые поля в ЕСТЬNULL ещё до округления:
ВЫРАЗИТЬ(ЕСТЬNULL(Продажи.Сумма, 0) КАК ЧИСЛО(15, 2))
Отдельный источник NULL — деление. В запросе деление на ноль не вызывает ошибку, а возвращает NULL, и этот NULL тянется в итоги. Знаменатель защищают через ВЫБОР:
ВЫБОР
КОГДА ЕСТЬNULL(Остатки.Количество, 0) = 0
ТОГДА 0
ИНАЧЕ ВЫРАЗИТЬ(Остатки.Сумма / Остатки.Количество КАК ЧИСЛО(15, 2))
КОНЕЦ
Порядок важен: сначала защита от NULL и нуля, потом деление, и только потом округление. Если сначала округлить, а защиту повесить снаружи, NULL уже успеет испортить промежуточный результат.
Округление в отчётах на СКД: строки против итогов
В отчётах округление чаще всего ставят в выражение ресурса. Там работает Окр, и округлить сумму до копеек можно прямо в настройке показателя: Окр(Сумма, 2).
Здесь всплывает нюанс, который ломает сверку. Сумма округлённых строк не обязана совпадать с округлённым итогом. Если округлить каждую строку по отдельности, а итог считать как их сумму, он может разойтись с округлённой суммой исходных значений на копейку-две за счёт накопления остатков.
Что с этим делать:
- Решите, что для отчёта первично — построчные значения или итог. В платёжных документах обычно первичны строки (их видит контрагент), в аналитике — итог.
- Если первичен итог, считайте его отдельным выражением от неокруглённой суммы, а не как сумму округлённых строк.
- Для документов с жёсткой сверкой заводят корректировку: разницу между итогом и суммой строк относят на последнюю строку.
В запросе это тоже учитывают: округлять лучше на том уровне детализации, который реально показывается, а не «на всякий случай» на каждом шаге вычислений.
Что быстрее: округлять в запросе или после выборки
ВЫРАЗИТЬ считается на стороне СУБД, пока набор ещё формируется, — это быстро даже на больших выборках. Окр в СКД отрабатывает уже после получения данных, на сервере 1С, поэтому на миллионах строк заметно тяжелее.
Отсюда рабочие правила:
- Где можно округлить в тексте запроса через
ВЫРАЗИТЬ— округляйте там. Окрв СКД держите для итогов и вычисляемых показателей, которых в запросе нет.- Не округляйте в условиях соединения и в секции ГДЕ. Функция поверх поля мешает СУБД использовать индекс, и запрос переходит на полный перебор таблицы.
- Не плодите промежуточные округления во временных таблицах, если результат всё равно округляется в конце, — это лишние проходы по данным.
Готовые примеры под частые задачи
Выделить НДС и округлить до копеек. Ставка 20%, сумма с налогом делится на 120 и умножается на 20:
ВЫРАЗИТЬ(Документ.СуммаСНДС * 20 / 120 КАК ЧИСЛО(15, 2)) КАК НДС
Для суммы 1180 получится 196,67 — проверка: 1180 * 20 / 120 = 196,6667, округление до двух знаков даёт 196,67.
Цена за единицу из суммы и количества с защитой от деления на ноль:
ВЫБОР
КОГДА ЕСТЬNULL(Строки.Количество, 0) = 0
ТОГДА 0
ИНАЧЕ ВЫРАЗИТЬ(Строки.Сумма / Строки.Количество КАК ЧИСЛО(15, 2))
КОНЕЦ КАК ЦенаЗаЕдиницу
Группировка аналитики с укрупнением до тысяч — чтобы в отчёте не пестрели копейки:
ВЫРАЗИТЬ(Обороты.Сумма / 1000 КАК ЧИСЛО(15, 0)) * 1000 КАК СуммаТыс
Пересчёт валютной суммы в рубли по курсу с округлением до копеек. В регистре курсов есть не только курс, но и кратность (для валют вроде йены курс задают за 100 единиц), поэтому делим на неё:
ВЫРАЗИТЬ(
Документ.СуммаВалюты * Курсы.Курс / Курсы.Кратность
КАК ЧИСЛО(15, 2)
) КАК СуммаРуб
Округление ставим один раз — на финальном результате пересчёта, а не на курсе: округлять курс отдельно нельзя, иначе набегает ошибка на больших суммах.
Частые вопросы
Есть ли в языке запросов функция ОКРУГЛ или Окр?
ВЫРАЗИТЬ(Выражение КАК ЧИСЛО(м, н)). Функции Окр и Цел доступны во встроенном языке и в выражениях СКД, но не внутри ВЫБРАТЬ … ИЗ.Почему ВЫРАЗИТЬ и Окр иногда округляют по-разному?
ВЫРАЗИТЬ считается на стороне СУБД, и поведение ровно на границе 0,5 зависит от базы (файловая или клиент-серверная). Окр считает движок 1С по своим правилам. Если копейка критична, фиксируйте способ округления и проверяйте его на контрольных суммах.Как отбросить дробную часть без округления прямо в запросе?
Цел() в СКД или во встроенном языке. В запросе приходится либо выносить расчёт, либо мириться с арифметическим округлением ВЫРАЗИТЬ.Как округлить до 50 копеек или до 5 рублей?
0,5: ВЫРАЗИТЬ(Сумма / 0.5 КАК ЧИСЛО(15, 0)) * 0.5. Для шага 5: делите и умножаете на 5.Влияет ли округление на скорость запроса?
ВЫРАЗИТЬ в списке полей почти бесплатно. Но округление в секции ГДЕ или в условиях соединения мешает использовать индексы и замедляет выборку — там его быть не должно.