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

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

В этой статье мы подробно разберем, как оптимизировать громоздкие вложенные ветвления, правильно добавить новые условия (на примере добавления ветки «Если Оплата за наличные и нет отсрочки платежа, то ИСТИНА»), а также рассмотрим критически важные нюансы работы с полями составного типа и значениями NULL.

Анализ исходной проблемы и выявление узких мест

Рассмотрим исходное условие, с которым работал автор темы. Ему требовалось определить булево поле в запросе (признак возможности отгрузки или применения условий):


ВЫБОР 
    КОГДА (Контрагенты.Код = "000001846" ИЛИ Контрагенты.Код = "УТ0007192" ИЛИ Контрагенты.Код = "УТ0006608" ИЛИ Контрагенты.Код = "УТ0008180") И НЕ РТУ.СвободныйТовар 
        ТОГДА ВЫБОР 
            КОГДА РТУ.ПрямаяДоставка 
                ТОГДА Заказ.ОплатаНал И ВЫБОР КОГДА ЕСТЬNULL(ЗначенияСвойствОбъектов.Значение, ЛОЖЬ) = ИСТИНА ТОГДА ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ 
            ИНАЧЕ ВЫБОР 
                КОГДА РТУ.Самовывоз ИЛИ РТУ.Транзит 
                    ТОГДА ВЫБОР КОГДА ЕСТЬNULL(ЗначенияСвойствОбъектов.Значение, ЛОЖЬ) = ИСТИНА ТОГДА ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ 
                ИНАЧЕ ЛОЖЬ 
            КОНЕЦ 
        КОНЕЦ 
    ИНАЧЕ ЛОЖЬ 
КОНЕЦ

Проанализировав данную конструкцию, мы можем выделить сразу три серьезные проблемы:

  1. Критическая вложенность (Anti-pattern): Конструкции ВЫБОР КОГДА вложены друг в друга на три уровня вглубь. Разобраться в приоритетах выполнения и логических связях при такой записи крайне тяжело.
  2. «Хардкод» кодов контрагентов: Проверка конкретных текстовых кодов (Контрагенты.Код = "000001846") напрямую в коде запроса противоречит стандартам разработки фирмы «1С». При изменении кодов в пользовательском режиме или переносе данных логика просто сломается.
  3. Избыточная и опасная работа с булевыми значениями: Конструкция ВЫБОР КОГДА ЕСТЬNULL(Поле, ЛОЖЬ) = ИСТИНА ТОГДА ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ написана крайне неоптимально. По сути, разработчик пытается сделать двойное отрицание булевой переменной.

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

Шаг 1. Безопасная работа с NULL и составными типами данных

Обратим внимание на попытки упростить проверку дополнительных свойств объектов. На форуме прозвучало предложение использовать конструкцию НЕ ЕСТЬNULL(ЗначенияСвойствОбъектов.Значение, ЛОЖЬ).

Выясним причину, почему такой подход может привести к аварийному завершению запроса. Поле Значение в таблице дополнительных реквизитов (ЗначенияСвойствОбъектов) имеет составной тип данных. Оно может содержать число, строку, ссылку на справочник или булево значение. Если для какого-то контрагента свойство заполнено, например, значением типа "СправочникСсылка.ФизическиеЛица" или строкой, то попытка применить логическое отрицание НЕ к этому значению вызовет синтаксическую ошибку СУБД (несоответствие типов данных).

Поэтому наиболее безопасным, лаконичным и отказоустойчивым решением в среде 1С является явное сравнение с ложью:

ЕСТЬNULL(ЗначенияСвойствОбъектов.Значение, ЛОЖЬ) = ЛОЖЬ

Давайте разберем, как это работает. Функция ЕСТЬNULL подменяет отсутствующее значение (если свойство не задано) на значение ЛОЖЬ. После этого СУБД производит сравнение результата с литералом ЛОЖЬ. Если значение было действительно пустым (или было заполнено значением ЛОЖЬ), выражение вернет ИСТИНА. Если же там находилась ссылка или число, то сравнение не-булевого значения с булевым просто вернет ЛОЖЬ, не вызывая критической ошибки выполнения.

Шаг 2. Избавляемся от жесткого кодирования (хардкода)

Согласно стандартам разработки «1С», любые списки предопределенных элементов или конкретных объектов должны передаваться в запрос в виде параметров. Вместо перечисления кодов контрагентов через ИЛИ, мы должны использовать параметр запроса &ОсобыеКонтрагенты, в который на уровне встроенного языка будет передан массив ссылок на нужных контрагентов.

В тексте запроса это будет выглядеть следующим образом:

Контрагенты.Ссылка В (&ОсобыеКонтрагенты)

Такой подход не только делает код чище, но и позволяет в будущем легко вынести настройку списка этих контрагентов в пользовательский интерфейс (например, через функциональные опции или константы).

Шаг 3. Рефакторинг и «выпрямление» структуры ВЫБОР КОГДА

Конструкция ВЫБОР КОГДА в языке запросов 1С работает по принципу классического оператора Если ... ИначеЕсли ... Иначе. Условия проверяются строго сверху вниз. Как только система наталкивается на первое истинное условие, она возвращает значение из ветки ТОГДА, а все последующие ветки полностью игнорируются.

Это ключевое свойство позволяет нам развернуть любые вложенные конструкции в плоский, линейный список условий, объединяя связанные проверки логическими операторами И и ИЛИ.

Давайте посмотрим, как упрощается исходная логика автора, если мы применим линейную структуру и добавим новое условие: "Если Оплата за наличные И нет отсрочки платежа, ТОГДА ИСТИНА".

Сформулируем плоские условия:

  1. Первый сценарий (Прямая доставка для особого контрагента): Контрагент входит в число особых, товар не свободный, доставка прямая, оплата наличными, и при этом признак отсрочки равен ЛОЖЬ. В этом случае возвращаем ИСТИНА.
  2. Второй сценарий (Самовывоз или Транзит для особого контрагента): Контрагент входит в число особых, товар не свободный, способ доставки — самовывоз или транзит, и признак отсрочки равен ЛОЖЬ. Возвращаем ИСТИНА.
  3. Третий сценарий (Новое общее условие автора): Для всех остальных контрагентов (или условий доставки) — если это оплата наличными и признак отсрочки равен ЛОЖЬ, то возвращаем ИСТИНА.
  4. В остальных случаях возвращаем ЛОЖЬ.

Итоговое оптимизированное решение

Объединив все вышеперечисленные шаги, мы получаем чистый, безопасный и легко поддерживаемый код запроса:


ВЫБОР
    // 1. Условие для особых контрагентов при прямой доставке
    КОГДА Контрагенты.Ссылка В (&ОсобыеКонтрагенты)
          И НЕ РТУ.СвободныйТовар
          И РТУ.ПрямаяДоставка
          И Заказ.ОплатаНал
          И ЕСТЬNULL(ЗначенияСвойствОбъектов.Значение, ЛОЖЬ) = ЛОЖЬ
        ТОГДА ИСТИНА

    // 2. Условие для особых контрагентов при самовывозе или транзите
    КОГДА Контрагенты.Ссылка В (&ОсобыеКонтрагенты)
          И НЕ РТУ.СвободныйТовар
          И (РТУ.Самовывоз ИЛИ РТУ.Транзит)
          И ЕСТЬNULL(ЗначенияСвойствОбъектов.Значение, ЛОЖЬ) = ЛОЖЬ
        ТОГДА ИСТИНА

    // 3. Новое общее условие: Оплата наличными при отсутствии отсрочки платежа
    КОГДА Заказ.ОплатаНал
          И ЕСТЬNULL(ЗначенияСвойствОбъектов.Значение, ЛОЖЬ) = ЛОЖЬ
        ТОГДА ИСТИНА

    ИНАЧЕ ЛОЖЬ
КОНЕЦ

Проанализируем преимущества получившейся конструкции перед исходной:

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

← На главную