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