Как исправить синтаксическую ошибку в условном выражении запроса 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При написании сложных запросов в платформе «1С:Предприятие» разработчики часто сталкиваются с ситуацией, когда требуется прибавить разное количество дней или изменить логику вычисления прямо в поле запроса в зависимости от некоторого условия. Если синтаксис конструкции ветвления составлен с ошибкой, платформа выдает сообщение: Синтаксическая ошибка "когда".

В этой статье мы подробно разберем причину возникновения данной ошибки, рассмотрим правильный синтаксис условного оператора в языке запросов 1С, а также проанализируем способы оптимизации кода и повышения производительности СУБД.

Причина ошибки и правильный синтаксис конструкции ВЫБОР

Проанализируем ситуацию, с которой столкнулся разработчик. В запросе предпринята попытка прибавить число дней к дате по следующему булеву условию:


КОГДА Пред.Номенклатура.ОМ_БезПечати = ИСТИНА
    ТОГДА ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), ДЕНЬ, 30)
ИНАЧЕ ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), ДЕНЬ, 3)
КОНЕЦ

При выполнении такого кода парсер языка запросов выдает синтаксическую ошибку. Выясним причину: в языке запросов 1С любое условное выражение ветвления должно обязательно начинаться с ключевого слова ВЫБОР. Без этого оператора синтаксический анализатор не может распознать конструкцию КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ.

Для исправления ошибки достаточно добавить ключевое слово ВЫБОР в самое начало условного блока:


ВЫБОР
    КОГДА Пред.Номенклатура.ОМ_БезПечати = ИСТИНА
        ТОГДА ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), ДЕНЬ, 30)
    ИНАЧЕ ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), ДЕНЬ, 3)
КОНЕЦ

Оптимизация синтаксиса и сокращение дублирования кода

Рассмотрим по шагам, как можно улучшить написанный фрагмент кода с точки зрения читаемости и лаконичности.

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

Посмотрим на обновленный и оптимизированный вариант запроса:


ДОБАВИТЬКДАТЕ(
    НАЧАЛОПЕРИОДА(ТоварыНаСкладах.Период, ДЕНЬ), 
    ДЕНЬ, 
    ВЫБОР 
        КОГДА Пред.Номенклатура.ОМ_БезПечати 
            ТОГДА 30 
        ИНАЧЕ 3 
    КОНЕЦ
)

Производительность запроса и нюансы работы с данными

Разберем важные аспекты производительности и корректности работы данного выражения на стороне СУБД:

1. Разыменование ссылок («обращение через точку»)
Конструкция вида Пред.Номенклатура.ОМ_БезПечати содержит двойное обращение к реквизитам через точку. На уровне СУБД платформа 1С автоматически создает два неявных левых соединения (LEFT JOIN). На больших объемах данных из таблиц регистров это может привести к ощутимому замедлению запроса. Чтобы избежать падения производительности, рекомендуется выполнять явные соединения (ЛЕВОЕ СОЕДИНЕНИЕ) с нужными таблицами справочников или предварительно выбирать данные во временные таблицы с индексацией по ссылочным полям.

2. Обработка значений NULL
Если в результате левого соединения поле Пред или Номенклатура окажется не заполнено, обращение к реквизиту вернет NULL. При сравнении в операторе КОГДА значение NULL не равен ИСТИНА, поэтому запрос автоматически перейдет в ветку ИНАЧЕ и прибавит 3 дня. Если такое поведение логически неприемлемо, следует задействовать функцию ЕСТЬNULL:


ВЫБОР 
    КОГДА ЕСТЬNULL(Пред.Номенклатура.ОМ_БезПечати, ЛОЖЬ) 
        ТОГДА 30 
    ИНАЧЕ 3 
КОНЕЦ

3. Избыточность обнуления времени
Если поле Период таблицы ТоварыНаСкладах хранит только дату или время в составе даты не критично для дальнейших вычислений, вызов НАЧАЛОПЕРИОДА(..., ДЕНЬ) является избыточным. Его удаление снизит вычислительную нагрузку на сервер баз данных.

← На главную