Округление в запросах и отчётах 1С: от ВЫРАЗИТЬ до Окр()

· 9 мин

Содержание

Внутри запроса округляет не функция Окр(), а оператор ВЫРАЗИТЬ: запись ВЫРАЗИТЬ(Сумма КАК ЧИСЛО(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. Решите, что для отчёта первично — построчные значения или итог. В платёжных документах обычно первичны строки (их видит контрагент), в аналитике — итог.
  2. Если первичен итог, считайте его отдельным выражением от неокруглённой суммы, а не как сумму округлённых строк.
  3. Для документов с жёсткой сверкой заводят корректировку: разницу между итогом и суммой строк относят на последнюю строку.

В запросе это тоже учитывают: округлять лучше на том уровне детализации, который реально показывается, а не «на всякий случай» на каждом шаге вычислений.

Что быстрее: округлять в запросе или после выборки

ВЫРАЗИТЬ считается на стороне СУБД, пока набор ещё формируется, — это быстро даже на больших выборках. Окр в СКД отрабатывает уже после получения данных, на сервере 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.
Влияет ли округление на скорость запроса?
Само по себе ВЫРАЗИТЬ в списке полей почти бесплатно. Но округление в секции ГДЕ или в условиях соединения мешает использовать индексы и замедляет выборку — там его быть не должно.