При составлении отчетов и обработке данных разработчикам регулярно приходится получать не просто хранящиеся в базе реквизиты, а вычисляемые показатели. Типичный пример — необходимость рассчитать объем работ на основе общей суммы выработки и расценки за единицу прямо в теле запроса.
Рассмотрим синтаксис арифметических операций в языке запросов платформы 1С:Предприятие, разберем базовый вариант решения, а также изучим критически важные аспекты: защиту от деления на ноль, обработку пустых значений NULL и управление точностью чисел.
Язык запросов 1С поддерживает стандартные математические операции: сложение (+), вычитание (-), умножение (*) и деление (/). Чтобы рассчитать новое поле, достаточно прописать выражение непосредственно в списке выборки полей и назначить ему псевдоним с помощью ключевого слова КАК.
Посмотрим на пример из исходного запроса, где требуется заменить выбор поля ВТТехОперации.Количество на результат отношения выработки к расценке:
ВЫБРАТЬ
ВТТехОперации.Значение КАК Сотрудник,
ВТПродукция.Ссылка КАК Документ,
ВТПродукция.Номенклатура КАК ВидПродукции,
ВТПродукция.ХарактеристикаНоменклатуры,
ВТПродукция.Количество КАК ОбъемПродукции,
ВТПродукция.ЕдиницаИзмерения,
ВТРаспределение.ТехнологическаяОперация КАК ВидРабот,
ВТРаспределение.Сумма / ВТТехОперации.Расценка КАК ОбъемРабот,
ВТТехОперации.Расценка,
ВТРаспределение.Сумма КАК Выработка
Если разработка ведется в визуальном конструкторе запросов, перейдем на вкладку Поля. Нажмем на кнопку добавления произвольного выражения (пиктограмма с зеленым карандашом) и введем текст формулы ВТРаспределение.Сумма / ВТТехОперации.Расценка, указав в колонке псевдонима имя ОбъемРабот.
Проанализируем потенциальную проблему прямого деления: если в таблице ВТТехОперации поле Расценка окажется равным нулю, СУБД аварийно прервет выполнение операции с критической ошибкой деление на ноль.
Чтобы запрос выполнялся стабильно при любых исходных данных, операцию деления всегда необходимо обрамлять в условную конструкцию ВЫБОР ... КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ.
Разберем безопасный вариант вычисления:
ВЫБОР
КОГДА ВТТехОперации.Расценка = 0 ТОГДА 0
ИНАЧЕ ВТРаспределение.Сумма / ВТТехОперации.Расценка
КОНЕЦ КАК ОбъемРабот
В реальных задачах данные часто извлекаются с применением левых или полных соединений. Если для записи из левой таблицы не нашлось соответствия в правой, все ее поля будут содержать значение NULL.
Выясним причину опасности: проверка Поле = 0 для значения NULL вернет Ложь. В результате условие перейдет в ветку ИНАЧЕ, что приведет к непредвиденному поведению или попытке деления на нечисловое значение. Кроме того, любая арифметическая операция с участием NULL дает NULL.
Для корректной работы применим функцию ЕСТЬNULL, подставляющую числовое значение по умолчанию:
ВЫБОР
КОГДА ЕСТЬNULL(ВТТехОперации.Расценка, 0) = 0 ТОГДА 0
ИНАЧЕ ЕСТЬNULL(ВТРаспределение.Сумма, 0) / ВТТехОперации.Расценка
КОНЕЦ КАК ОбъемРабот
В языке запросов 1С нет прямого аналога функции Окр(). При выполнении деления результат может содержать непредсказуемое число знаков после запятой или вызывать переполнение разрядности чисел в СУБД. Для явного ограничения точности и корректного округления используем конструкцию ВЫРАЗИТЬ(... КАК ЧИСЛО(Длина, Точность)).
Посмотрим на итоговый, полностью защищенный вариант выражения:
ВЫРАЗИТЬ(
ВЫБОР
КОГДА ЕСТЬNULL(ВТТехОперации.Расценка, 0) = 0 ТОГДА 0
ИНАЧЕ ЕСТЬNULL(ВТРаспределение.Сумма, 0) / ВТТехОперации.Расценка
КОНЕЦ
КАК ЧИСЛО(15, 3)
) КАК ОбъемРабот
Конструкция ВЫРАЗИТЬ приведет результат к типу Число разрядностью 15 знаков с 3 знаками после запятой, выполнив округление по правилам математики на уровне базы данных.
Рассмотрим, когда расчет не следует переносить непосредственно в текст запроса:
Сумма(Выработка) / Выбор Когда Сумма(Расценка) = 0 Тогда 1 Иначе Сумма(Расценка) Конец.Окр().