При написании сложных запросов в платформе 1С разработчики часто сталкиваются с ситуацией, когда конструкция ВЫБОР КОГДА ... КОНЕЦ вместе с математическими вычислениями возвращает нулевой результат, значение NULL или уходит не в ту ветку условия. Проанализируем типичные ошибки, из-за которых формулы в запросе отказываются работать, и разберем способы их устранения.
Разберем основные факторы, влияющие на расчет результатов в языке запросов 1С:
NULL, дает в результате NULL. Общая обертка вида ЕСТЬNULL(A + B + C, 0) не работает так, как ожидает разработчик: если хотя бы один из операндов равен NULL, всё выражение внутри функции принимает значение NULL, и внешняя функция просто возвращает итоговый ноль.ВТ.Остатки содержит NULL (например, после левого соединения), то выражение ВТ.Остатки <> 0 или ВТ.Остатки > 0 возвращает значение НЕОПРЕДЕЛЕНО. Конструкция ВЫБОР воспринимает его как ЛОЖЬ и всегда выполняет ветку ИНАЧЕ.&ПериодДней или поле ВТ.СрокДоставки переданы как Дата, а не Число, СУБД не сможет выполнить расчет или выдаст ошибку.ЕСТЬNULL подменяет отсутствие значения, но не защищает от ситуаций, когда делитель физически равен числовому нулю (0).Рассмотрим пример ошибочного кода, в котором функция ЕСТЬNULL применена ко всему математическому выражению целиком:
ВЫБОР
КОГДА ВТ.Остатки <> 0
ТОГДА ЕСТЬNULL(ВТ.Продажи / &ПериодДней * ВТ.СрокДоставки + ВТ.МПО + ВТ.Продажи, 0)
ИНАЧЕ ЕСТЬNULL(ВТ.Продажи / &ПериодДней * ВТ.СрокДоставки - ВТ.Остатки + ВТ.МПО + ВТ.Продажи, 0)
КОНЕЦ КАК Результат
Если хотя бы одно из полей (например, ВТ.МПО или ВТ.СрокДоставки) равно NULL, всё выражение обнуляется. Чтобы исправить эту ситуацию, необходимо применить ЕСТЬNULL к каждому полю отдельно, а также обработать условие сравнения:
ВЫБОР
КОГДА ЕСТЬNULL(ВТ.Остатки, 0) <> 0
ТОГДА ЕСТЬNULL(ВТ.Продажи, 0) / &ПериодДней * ЕСТЬNULL(ВТ.СрокДоставки, 0) + ЕСТЬNULL(ВТ.МПО, 0) + ЕСТЬNULL(ВТ.Продажи, 0)
ИНАЧЕ ЕСТЬNULL(ВТ.Продажи, 0) / &ПериодДней * ЕСТЬNULL(ВТ.СрокДоставки, 0) - ЕСТЬNULL(ВТ.Остатки, 0) + ЕСТЬNULL(ВТ.МПО, 0) + ЕСТЬNULL(ВТ.Продажи, 0)
КОНЕЦ КАК Результат
Чтобы не нагромождать итоговый запрос многочисленными вызовами функций, рекомендуется заменять NULL на 0 на этапе формирования временных таблиц. В таком случае итоговые формулы остаются чистыми и легкочитаемыми.
Посмотрим на пример заменяющего выражения во временной таблице:
ВЫБРАТЬ
Продажи.Номенклатура КАК Номенклатура,
ЕСТЬNULL(Продажи.Количество, 0) КАК Продажи,
ЕСТЬNULL(Остатки.Количество, 0) КАК Остатки,
ЕСТЬNULL(Сроки.Дней, 0) КАК СрокДоставки,
ЕСТЬNULL(МПО.Количество, 0) КАК МПО
ПОМЕСТИТЬ ВТ_Данные
ИЗ
...
После этого в основном запросе вычисления можно делать без постоянной проверки каждого поля.
Выясним, на что еще необходимо обратить внимание при составлении математических выражений:
&ПериодДней передается в запрос именно как тип Число. Если в параметре передана дата, следует предварительно рассчитать количество дней в коде 1С или воспользоваться функцией РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, ДЕНЬ).&ПериодДней может быть равен нулю, следует добавить проверку условия в запрос:
ВЫБОР
КОГДА &ПериодДней = 0 ТОГДА 0
ИНАЧЕ ... // исходная формула
КОНЕЦ
ВЫРАЗИТЬ(Результат КАК ЧИСЛО(15, 2)).