Округление в языке запросов 1С: функции, обходные приёмы и подводные камни СУБД

· 10 мин

Содержание

Чтобы округлить число в запросе 1С, используйте функцию ОКР(Число, Разрядность): ОКР(Цена * 1.2, 2) вернёт сумму до копеек. Целую часть даёт ЦЕЛ(Число). Обе функции появились в языке запросов в платформе 8.3.20. На более ранних платформах число в запросе округляют приведением типа: ВЫРАЗИТЬ(Сумма КАК ЧИСЛО(15, 2)).

Готовых ОКРВВЕРХ и ОКРВНИЗ в языке запросов 1С нет. Округление вверх и вниз собирают из ЦЕЛ и конструкции ВЫБОР. Ниже — рабочие выражения для каждого случая и то, где округление в запросе даёт неожиданный результат.

Функция ОКР: обычное округление числа в запросе

ОКР округляет по школьным правилам: пятёрка уходит вверх по модулю. Синтаксис:

ОКР(<Выражение>, <Разрядность>)
  • 🔢 <Выражение> — поле, параметр или арифметика над ними;
  • 🎯 <Разрядность> — сколько знаков оставить после запятой. 0 — до целых, 2 — до копеек.

Пример: цена с наценкой 17,5 % до копеек.

ВЫБРАТЬ
    Номенклатура.Ссылка КАК Товар,
    ОКР(Цены.Цена * 1.175, 2) КАК ЦенаСНаценкой
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ) КАК Цены
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
        ПО Цены.Номенклатура = Номенклатура.Ссылка

Проверим на числах. Цена 100,30: 100,30 × 1,175 = 117,8525. ОКР(…, 2) даёт 117,85. Цена 99,90: 99,90 × 1,175 = 117,3825, результат 117,38.

Регистр и поля в примере условные — подставьте свои. Важен приём: множьте и округляйте в одном выражении, тогда в выборку уходит уже готовая сумма.

Округлять до десятков или сотен удобнее через деление: ОКР(Сумма / 100, 0) * 100. Из 1 249 получится 1 200, из 1 250 — 1 300. Так выражение читается однозначно и не зависит от того, примет ли СУБД отрицательную разрядность.

Если платформа старше 8.3.20

На платформе с номером ниже 8.3.20 ОКР в запросе вызовет ошибку синтаксиса. То же бывает на новой платформе, если у конфигурации включён режим совместимости с более ранней версией. Проверить его можно в конфигураторе: свойства корня конфигурации → Режим совместимости.

Менять режим совместимости ради одной функции в типовой конфигурации не стоит. Для таких баз есть приём с ВЫРАЗИТЬ, он разобран ниже.

ЦЕЛ, округление вверх и вниз в запросе 1С

ЦЕЛ(Число) отбрасывает дробную часть. Это не округление вниз, а усечение к нулю:

ЧислоЦЕЛОкругление внизОкругление вверх
7,3778
7,0777
−7,3−7−8−7

Для положительных чисел ЦЕЛ и округление вниз совпадают. Расходятся они только на отрицательных. Это важно для остатков, сторно и корректировок, где минус — обычное дело.

Округление вверх (аналог ОКРВВЕРХ)

Типичная задача — сколько упаковок нужно, чтобы покрыть потребность. 25 штук при упаковке по 12 — это 3 упаковки, а не 2.

ВЫБОР
    КОГДА Потребность / Кратность = ЦЕЛ(Потребность / Кратность)
        ТОГДА Потребность / Кратность
    ИНАЧЕ ЦЕЛ(Потребность / Кратность) + 1
КОНЕЦ КАК Упаковок

Проверка: 25 / 12 = 2,083…; ЦЕЛ = 2; дробь есть, значит 2 + 1 = 3. При потребности 24 частное ровно 2, ответ 2.

Выражение рассчитано на положительные числа. Если в данных бывает минус, добавьте ветку:

ВЫБОР
    КОГДА Х = ЦЕЛ(Х) ТОГДА Х
    КОГДА Х > 0 ТОГДА ЦЕЛ(Х) + 1
    ИНАЧЕ ЦЕЛ(Х)
КОНЕЦ

Здесь Х — ваше выражение. Для −7,3 сработает третья ветка: ЦЕЛ даст −7, это и есть округление вверх.

Округление вниз (аналог ОКРВНИЗ)

ВЫБОР
    КОГДА Х = ЦЕЛ(Х) ТОГДА Х
    КОГДА Х < 0 ТОГДА ЦЕЛ(Х) - 1
    ИНАЧЕ ЦЕЛ(Х)
КОНЕЦ

Для 7,3 ответ 7, для −7,3 ответ −8.

Вверх или вниз до копеек

Тот же приём работает с любой разрядностью. Умножьте на 100, округлите до целого, разделите обратно. Округление вниз до копеек для положительной суммы:

ЦЕЛ(Сумма * 100) / 100

Сумма 152,4791 → 15 247,91 → 15 247 → 152,47.

Округление в запросе на старых платформах: приём с ВЫРАЗИТЬ

До 8.3.20 единственный штатный способ округлить в запросе — привести число к типу с меньшей точностью:

ВЫРАЗИТЬ(Сумма * 1.2 КАК ЧИСЛО(15, 2))

Лишние знаки после запятой отсекаются с округлением. 1 000,005 превратится в 1 000,01, а 99,994 — в 99,99. Вторым параметром ЧИСЛО(15, 2) задают число знаков, первым — общую длину.

Длину берите с запасом. Если результат не помещается в ЧИСЛО(15, 2), то есть в нём больше 13 цифр до запятой, запрос завершится ошибкой переполнения. Для оборотов крупной компании за год ставьте ЧИСЛО(20, 2) или больше.

Целая часть через ВЫРАЗИТЬ

ВЫРАЗИТЬ(Х КАК ЧИСЛО(15, 0)) даёт ближайшее целое, а не целую часть. Чтобы получить усечение, на старых платформах вычитали почти половину:

ВЫРАЗИТЬ(Х - 0.4999999 КАК ЧИСЛО(15, 0))

Для 7,3: 6,8000001 → 7. Для 7,9: 7,4000001 → 7. Для 7,0: 6,5000001 → 7.

Приём рабочий, но с оговорками:

  • ❗ подходит только для положительных чисел;
  • ❗ точность ограничена числом девяток: значение 7,99999995 даст 8, а не 7;
  • ❗ выражение плохо читается, через год никто не вспомнит, откуда 0,4999999.

Округление вверх на старой платформе — тот же приём с плюсом: ВЫРАЗИТЬ(Х + 0.4999999 КАК ЧИСЛО(15, 0)). Для 2,083 получится 3, для ровного 2 — тоже 2.

Если платформа позволяет, переходите на ОКР и ЦЕЛ: они честно обрабатывают и отрицательные значения, и любое число знаков.

Как СУБД считает числа и почему результат «плывёт»

Запрос 1С не выполняется сам по себе. Платформа переводит его в SQL, а считает уже СУБД: файловая база, MS SQL Server или PostgreSQL. Отсюда несколько эффектов, которых нет во встроенном языке.

Точность деления

Результат деления в запросе имеет ограниченное число знаков после запятой. Сколько именно — зависит от СУБД и типов операндов. Поэтому 1 / 3 * 3 может дать не ровно 1, а 0,999999…

Правило простое: сначала умножайте, потом делите.

ВыражениеЧто получится
Сумма / Количество * 100промежуточное частное уже усечено, ошибка множится на 100
Сумма * 100 / Количестводеление последним, потеря точности минимальна

Если результат деления дальше участвует в расчётах, оберните его в ОКР до нужной точности сразу. Так все последующие операции работают с предсказуемым числом.

Деление на ноль

Деление на поле, где встречается 0, ломает весь запрос, а не одну строку. Защищайтесь заранее:

ВЫБОР
    КОГДА Количество = 0 ТОГДА 0
    ИНАЧЕ ОКР(Сумма / Количество, 2)
КОНЕЦ КАК Цена

NULL в арифметике

Любая операция с NULL даёт NULL. После левого соединения пустое поле превратит ОКР(Цена * Количество, 2) в пустоту. Оберните поле в ЕСТЬNULL(Цены.Цена, 0) до умножения.

Одна база — разные СУБД

Если база переезжает с файлового варианта на MS SQL или PostgreSQL, сверьте контрольные отчёты. Целые суммы совпадут. Расхождения, если появятся, будут в последних знаках после длинных делений. Чем раньше в выражении стоит ОКР, тем меньше таких сюрпризов.

Сочетание функций округления в одном выражении

Округление до заданного шага

Цены в рознице часто ставят кратными 5 или 10 рублям. Общая формула для шага &Шаг:

ОКР(Цена / &Шаг, 0) * &Шаг

При шаге 5: 147,30 / 5 = 29,46 → 29 → 145. Цена 148,00: 29,6 → 30 → 150.

Нужна «психологическая» цена вида 149, 199, 249? Округлите вверх до 50 и вычтите рубль. Цена 173: 173 / 50 = 3,46, вверх → 4, 4 × 50 = 200, минус 1 = 199.

Округлить до итога или после

Порядок округления и группировки меняет сумму. Возьмём три строки по 33,333:

ПодходВыражениеИтог
Сначала округлить, потом сложитьСУММА(ОКР(Сумма, 2))33,33 × 3 = 99,99
Сначала сложить, потом округлитьОКР(СУММА(Сумма), 2)99,999 → 100,00

Ни один вариант не ошибочен. Выбор зависит от того, с чем сверяетесь. Документ хранит суммы по строкам уже округлёнными, поэтому для сверки с документами нужен первый вариант. Для аналитики по «сырым» коэффициентам — второй.

Копейка на последнюю строку

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

Пример: 100 рублей на три подразделения поровну. Доли 33,33 + 33,33 + 33,33 = 99,99. Копейка уходит в первую строку: 33,34.

Сравнение способов округлить число в запросе

ЗадачаПлатформа 8.3.20 и новееПлатформа ниже 8.3.20Отрицательные числа
Математическое округление до N знаковОКР(Х, N)ВЫРАЗИТЬ(Х КАК ЧИСЛО(15, N))корректно в обоих
Целая часть (усечение)ЦЕЛ(Х)ВЫРАЗИТЬ(Х - 0.4999999 КАК ЧИСЛО(15, 0))старый приём — нет
Округление вверхВЫБОР + ЦЕЛВЫРАЗИТЬ(Х + 0.4999999 …)нужна ветка для минуса
Округление внизВЫБОР + ЦЕЛстарый приём для усечениянужна ветка для минуса
До шага (5, 10, 100)ОКР(Х / Шаг, 0) * ШагВЫРАЗИТЬ(Х / Шаг КАК ЧИСЛО(15, 0)) * Шагкорректно
Где вам нужно округление?

Запрос или встроенный язык: где округлять

Во встроенном языке у функции Окр есть третий параметр — режим округления. РежимОкругления.Окр15как20 округляет пятёрку вверх, РежимОкругления.Окр15как10 — вниз. В запросе такого выбора нет.

Округляйте в запросе, когда:

  • 📊 по округлённому значению идёт отбор, группировка или соединение;
  • 🧮 выборка большая, и пересчитывать её циклом дорого;
  • 📄 результат запроса сразу уходит в компоновку данных как ресурс.

Округляйте в коде, когда:

  • 🔁 нужен режим, где пятёрка уходит вниз;
  • 💰 надо разнести копейки остатка;
  • 🧩 правило округления зависит от настроек, которые проще проверить в коде, чем в ВЫБОР.

Отбор по округлённому значению — частый повод округлить именно в запросе. Например, ГДЕ ОКР(Остаток, 3) <> 0 отсекает «пыль» вида 0,0000001 в регистрах с дробным количеством. Без округления такие строки попадут в отчёт как ненулевые остатки.

Почему округление в запросе не работает: разбор ошибок

Диагностика: выберите симптом

Частые вопросы

Работает ли ОКР в запросе на файловой базе?
Да. Функция доступна во всех вариантах работы, если платформа 8.3.20 или новее и режим совместимости этого не запрещает.
Можно ли в запросе округлять с отрицательной разрядностью, как во встроенном языке?
Надёжнее делить и умножать: ОКР(Х / 100, 0) * 100 даёт округление до сотен одинаково на любой СУБД.
Есть ли в запросе банковское округление?
Нет, режима округления в запросе нет. Если нужно округление пятёрки к чётному или вниз, делайте его во встроенном языке через Окр с параметром РежимОкругления.
Можно ли использовать ОКР в условии ГДЕ и в ИМЕЮЩИЕ?
Можно. Учтите, что выражение над полем в ГДЕ мешает СУБД использовать индекс, на больших таблицах это замедлит запрос.
Поддерживает ли конструктор запросов функции ОКР и ЦЕЛ?
На новых платформах выражение с ними можно написать в поле вычисляемого выражения конструктора. На старых платформах такой текст конструктор не примет.