Как правильно использовать вложенные условия ВЫБОР КОГДА в запросах 1С?

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

При написании сложных запросов в системе «1С:Предприятие» разработчики регулярно сталкиваются с необходимостью проверять несколько зависимых условий подряд. Стандартная конструкция ВЫБОР КОГДА отлично подходит для простых развилок, но когда логика усложняется, возникает соблазн вложить одну проверку внутрь другой. В этой статье мы подробно разберем, как правильно реализовать вложенный выбор, проанализируем альтернативные подходы к построению запросов, а также изучим стандарты разработки фирмы «1С» для обеспечения максимальной производительности системы.

Разбор синтаксической ошибки: почему не работает простой вложенный КОГДА?

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


ВЫБОР
    КОГДА ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) = 0 
          И ЕСТЬNULL(ТоварыНаСкладахОстаткиПоставщик.КоличествоОстаток, 0) = 0 ТОГДА     
         КОГДА ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) = 0 ТОГДА
              Цена2
         Иначе
              ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0)
         Конец
КОНЕЦ КАК Цена

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

Правильный синтаксис вложенного ВЫБОРА

Посмотрим на пример правильного оформления вложенной проверки. Для того чтобы запрос успешно прошел синтаксический контроль платформы, мы должны явно указать вложенный оператор ВЫБОР:


ВЫБОР 
    КОГДА ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) = 0 
          И ЕСТЬNULL(ТоварыНаСкладахОстаткиПоставщик.КоличествоОстаток, 0) = 0 ТОГДА
        
        // Начинаем полноценный вложенный выбор
        ВЫБОР 
            КОГДА ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) = 0 ТОГДА 
                Цена2
            ИНАЧЕ 
                ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0)
        КОНЕЦ

    ИНАЧЕ 
        // Возвращаем значение по умолчанию, если остатки есть
        0
КОНЕЦ КАК Цена

Обратите внимание на то, как закрываются блоки: каждый открытый оператор ВЫБОР должен иметь свой собственный закрывающий КОНЕЦ. Вложенный блок закрывается первым, а внешний — в самом конце выражения. Это классическое решение, которое позволяет гибко выстраивать иерархию условий. Для практического применения сложных логических конструкций можно ознакомиться с примером составления запроса с множественными условиями.

Альтернативный вариант: «Плоская» структура без вложений

Хотя вложенный ВЫБОР полностью работоспособен, на практике код с глубокой вложенностью становится крайне тяжелым для чтения и поддержки. Опытные разработчики рекомендуют избавляться от вложений там, где это возможно, переводя структуру запроса в «плоский» вид. Мы можем добиться этого, объединив внешние и внутренние условия с помощью логического оператора И. Проанализируем, как будет выглядеть такой запрос:


ВЫБОР
    КОГДА ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) = 0 
          И ЕСТЬNULL(ТоварыНаСкладахОстаткиПоставщик.КоличествоОстаток, 0) = 0 
          И ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) = 0 ТОГДА    
         Цена2

    КОГДА ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) = 0 
          И ЕСТЬNULL(ТоварыНаСкладахОстаткиПоставщик.КоличествоОстаток, 0) = 0 
          И ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) <> 0 ТОГДА    
         ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0)

    ИНАЧЕ
         0
КОНЕЦ КАК Цена

Давайте сравним эти два подхода, чтобы понять их сильные и слабые стороны:

  1. Читаемость кода: «Плоская» структура читается линейно, сверху вниз, что облегчает ее понимание другими разработчиками. В ней меньше вложенных блоков, а значит, ниже риск запутаться в расстановке ключевых слов КОНЕЦ.
  2. Дублирование кода: Главный минус плоской структуры — необходимость повторения условий. Как видно из примера, нам пришлось дважды написать проверку равенства остатков нулю. Если условия изменятся, придется вносить правки в нескольких местах, что увеличивает риск человеческой ошибки.
  3. Производительность СУБД: Современные системы управления базами данных (СУБД) оптимизируют выполнение планов запросов, однако при вложенной структуре логика вычислений более очевидна. СУБД сначала проверяет внешнее условие, и если оно ложно, то вложенные выражения даже не вычисляются. В плоской структуре СУБД может тратить ресурсы на избыточные логические проверки, если оптимизатор не сработает должным образом.

Золотой стандарт 1С: вынесение условий во временные таблицы

Если ваши условия проверки содержат множество обращений через точку, тяжелые функции вроде ЕСТЬNULL или математические вычисления, то и вложенный, и плоский варианты будут перегружать СУБД. В соответствии с лучшими практиками разработки «1С» такие запросы необходимо оптимизировать с помощью временных таблиц.

Разберем этот процесс по шагам:

  1. Шаг 1. Предварительный расчет во временной таблице. В первом запросе пакета мы выбираем необходимые поля, избавляемся от значений NULL и сразу формируем простые булевы флаги. Например, мы можем заранее определить, равен ли остаток нулю, и поместить этот результат в отдельную колонку.
  2. Шаг 2. Итоговая выборка. Во втором запросе пакета мы читаем данные из подготовленной временной таблицы и строим конструкцию ВЫБОР на основе уже вычисленных простых полей (флагов).

Посмотрим на пример реализации этого паттерна:


// Запрос 1: Подготовка данных во временную таблицу ВТ_ПодготовленныеДанные
ВЫБРАТЬ
    Товары.Ссылка КАК Номенклатура,
    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) = 0 
        И ЕСТЬNULL(ОстаткиПоставщика.КоличествоОстаток, 0) = 0 КАК НетОстатков,
    ЕСТЬNULL(Цены.Цена, 0) КАК ЦенаСреза,
    ЕСТЬNULL(Цены.Цена, 0) = 0 КАК ЦенаРавнаНулю,
    Товары.Цена2 КАК ЦенаРезервная
ПОМЕСТИТЬ ВТ_ПодготовленныеДанные
ИЗ
    Справочник.Номенклатура КАК Товары
    // Здесь описываются необходимые соединения с таблицами остатков и цен
;

// Запрос 2: Финальный выбор с использованием простых флагов
ВЫБРАТЬ
    Данные.Номенклатура,
    ВЫБОР
        КОГДА Данные.НетОстатков ТОГДА
            ВЫБОР
                КОГДА Данные.ЦенаРавнаНулю ТОГДА Данные.ЦенаРезервная
                ИНАЧЕ Данные.ЦенаСреза
            КОНЕЦ
        ИНАЧЕ
            0
    КОНЕЦ КАК Цена
ИЗ
    ВТ_ПодготовленныеДанные КАК Данные

Такой подход значительно упрощает чтение кода запроса, позволяет СУБД эффективно строить планы выполнения за счет индексации временных таблиц и исключает многократные вычисления одних и тех же функций над физическими таблицами БД. Дополнительно повысить быстродействие при работе с масштабными базами ERP поможет многопоточная свёртка 1С:ERP для ускорения работы.

Важные правила работы с конструкцией ВЫБОР в запросах

При написании любых условий с использованием оператора ВЫБОР критически важно помнить о следующих нюансах:

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

Применяя на практике эти простые правила, вы не только решите текущую задачу по вложению условий, но и сделаете свой код надежным, быстрым и понятным для всей команды разработки. Чтобы гарантировать надежность данных после оптимизации сложных запросов, рекомендуется использовать автоматическую сверку бухгалтерских и налоговых проводок между базами.

← На главную