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