При написании сложных запросов в платформе «1С:Предприятие» разработчики часто сталкиваются с ситуацией, когда требуется прибавить разное количество дней или изменить логику вычисления прямо в поле запроса в зависимости от некоторого условия. Если синтаксис конструкции ветвления составлен с ошибкой, платформа выдает сообщение: Синтаксическая ошибка "когда".
В этой статье мы подробно разберем причину возникновения данной ошибки, рассмотрим правильный синтаксис условного оператора в языке запросов 1С, а также проанализируем способы оптимизации кода и повышения производительности СУБД.
Проанализируем ситуацию, с которой столкнулся разработчик. В запросе предпринята попытка прибавить число дней к дате по следующему булеву условию:
КОГДА Пред.Номенклатура.ОМ_БезПечати = ИСТИНА
ТОГДА ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), ДЕНЬ, 30)
ИНАЧЕ ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), ДЕНЬ, 3)
КОНЕЦ
При выполнении такого кода парсер языка запросов выдает синтаксическую ошибку. Выясним причину: в языке запросов 1С любое условное выражение ветвления должно обязательно начинаться с ключевого слова ВЫБОР. Без этого оператора синтаксический анализатор не может распознать конструкцию КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ.
Для исправления ошибки достаточно добавить ключевое слово ВЫБОР в самое начало условного блока:
ВЫБОР
КОГДА Пред.Номенклатура.ОМ_БезПечати = ИСТИНА
ТОГДА ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), ДЕНЬ, 30)
ИНАЧЕ ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), ДЕНЬ, 3)
КОНЕЦ
Рассмотрим по шагам, как можно улучшить написанный фрагмент кода с точки зрения читаемости и лаконичности.
= ИСТИНА. Значение поля само по себе является логическим выражением. Нам достаточно оставить только имя поля: КОГДА Пред.Номенклатура.ОМ_БезПечати ТОГДА.ДОБАВИТЬКДАТЕ и НАЧАЛОПЕРИОДА полностью дублируется в обеих ветках условий. Изменяется только третий параметр — количество добавляемых дней (30 или 3). Конструкцию ВЫБОР можно передать непосредственно в третий аргумент функции ДОБАВИТЬКДАТЕ.Посмотрим на обновленный и оптимизированный вариант запроса:
ДОБАВИТЬКДАТЕ(
НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ),
ДЕНЬ,
ВЫБОР
КОГДА Пред.Номенклатура.ОМ_БезПечати
ТОГДА 30
ИНАЧЕ 3
КОНЕЦ
)
Разберем важные аспекты производительности и корректности работы данного выражения на стороне СУБД:
1. Разыменование ссылок («обращение через точку»)
Конструкция вида Пред.Номенклатура.ОМ_БезПечати содержит двойное обращение к реквизитам через точку. На уровне СУБД платформа 1С автоматически создает два неявных левых соединения (LEFT JOIN). На больших объемах данных из таблиц регистров это может привести к ощутимому замедлению запроса. Чтобы избежать падения производительности, рекомендуется выполнять явные соединения (ЛЕВОЕ СОЕДИНЕНИЕ) с нужными таблицами справочников или предварительно выбирать данные во временные таблицы с индексацией по ссылочным полям.
2. Обработка значений NULL
Если в результате левого соединения поле Пред или Номенклатура окажется не заполнено, обращение к реквизиту вернет NULL. При сравнении в операторе КОГДА значение NULL не равен ИСТИНА, поэтому запрос автоматически перейдет в ветку ИНАЧЕ и прибавит 3 дня. Если такое поведение логически неприемлемо, следует задействовать функцию ЕСТЬNULL:
ВЫБОР
КОГДА ЕСТЬNULL(Пред.Номенклатура.ОМ_БезПечати, ЛОЖЬ)
ТОГДА 30
ИНАЧЕ 3
КОНЕЦ
3. Избыточность обнуления времени
Если поле Период таблицы ТоварыНаСкладах хранит только дату или время в составе даты не критично для дальнейших вычислений, вызов НАЧАЛОПЕРИОДА(..., ДЕНЬ) является избыточным. Его удаление снизит вычислительную нагрузку на сервер баз данных.