При написании сложных запросов в системе «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
КОНЕЦ КАК Цена
Давайте сравним эти два подхода, чтобы понять их сильные и слабые стороны:
КОНЕЦ.Если ваши условия проверки содержат множество обращений через точку, тяжелые функции вроде ЕСТЬNULL или математические вычисления, то и вложенный, и плоский варианты будут перегружать СУБД. В соответствии с лучшими практиками разработки «1С» такие запросы необходимо оптимизировать с помощью временных таблиц.
Разберем этот процесс по шагам:
NULL и сразу формируем простые булевы флаги. Например, мы можем заранее определить, равен ли остаток нулю, и поместить этот результат в отдельную колонку.ВЫБОР на основе уже вычисленных простых полей (флагов).Посмотрим на пример реализации этого паттерна:
// Запрос 1: Подготовка данных во временную таблицу ВТ_ПодготовленныеДанные
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) = 0
И ЕСТЬNULL(ОстаткиПоставщика.КоличествоОстаток, 0) = 0 КАК НетОстатков,
ЕСТЬNULL(Цены.Цена, 0) КАК ЦенаСреза,
ЕСТЬNULL(Цены.Цена, 0) = 0 КАК ЦенаРавнаНулю,
Товары.Цена2 КАК ЦенаРезервная
ПОМЕСТИТЬ ВТ_ПодготовленныеДанные
ИЗ
Справочник.Номенклатура КАК Товары
// Здесь описываются необходимые соединения с таблицами остатков и цен
;
// Запрос 2: Финальный выбор с использованием простых флагов
ВЫБРАТЬ
Данные.Номенклатура,
ВЫБОР
КОГДА Данные.НетОстатков ТОГДА
ВЫБОР
КОГДА Данные.ЦенаРавнаНулю ТОГДА Данные.ЦенаРезервная
ИНАЧЕ Данные.ЦенаСреза
КОНЕЦ
ИНАЧЕ
0
КОНЕЦ КАК Цена
ИЗ
ВТ_ПодготовленныеДанные КАК Данные
Такой подход значительно упрощает чтение кода запроса, позволяет СУБД эффективно строить планы выполнения за счет индексации временных таблиц и исключает многократные вычисления одних и тех же функций над физическими таблицами БД. Дополнительно повысить быстродействие при работе с масштабными базами ERP поможет многопоточная свёртка 1С:ERP для ускорения работы.
При написании любых условий с использованием оператора ВЫБОР критически важно помнить о следующих нюансах:
КОГДА не выполнилось, а секция ИНАЧЕ отсутствует в коде, запрос вернет значение NULL. В дальнейшем это может привести к непредсказуемым ошибкам в коде (например, при попытке сложить число с полученным NULL). Всегда явно указывайте дефолтное значение в ветке ИНАЧЕ.ВЫБОР КОГДА в секции фильтрации ГДЕ или в условиях соединения таблиц ПО категорически не рекомендуется. Такое написание делает невозможным использование индексов таблиц СУБД, приводя к полному сканированию таблиц (Table Scan) и колоссальным задержкам на крупных информационных базах. Заменяйте такие конструкции стандартной булевой логикой (операторами И, ИЛИ, НЕ) или формируйте текст запроса динамически на встроенном языке.Применяя на практике эти простые правила, вы не только решите текущую задачу по вложению условий, но и сделаете свой код надежным, быстрым и понятным для всей команды разработки. Чтобы гарантировать надежность данных после оптимизации сложных запросов, рекомендуется использовать автоматическую сверку бухгалтерских и налоговых проводок между базами.