Как в запросе 1С реализовать игнорирование условия в конструкции ВЫБОР КОГДА ... ИНАЧЕ?

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

При написании сложных запросов в 1С разработчики часто сталкиваются с необходимостью реализовать динамические связи между таблицами. Одна из распространенных ситуаций — необходимость наложить условие соединения только в том случае, если определенное поле или параметр заполнены. Если же значение пустое, условие должно игнорироваться, пропуская все записи.

Давайте подробно разберем, как правильно использовать конструкцию ВЫБОР (CASE) внутри секции связей таблиц, рассмотрим "магический" вариант с ИСТИНА, проанализируем альтернативы с логическим ИЛИ и, самое главное, обсудим влияние этих методов на производительность системы.

Суть проблемы: опциональное условие в связях

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

  1. Если в первой таблице (например, втМаршрутный) указан конкретный "ФильтрТорговыйПредставитель", то мы должны соединиться со второй таблицей строго по этому представителю.
  2. Если же в поле "ФильтрТорговыйПредставитель" находится пустая ссылка, то это условие нужно проигнорировать (считать выполненным для любой строки), полагаясь только на остальные условия связи.

Попытка использовать стандартную конструкцию ВЫБОР часто ставит в тупик именно на моменте описания ветки ИНАЧЕ.


|    И (ВЫБОР
|        КОГДА НЕ втМаршрутный.Фильтр = ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка)
|            ТОГДА втМаршрутный.Фильтр = Таблица2.Ответственный
|        ИНАЧЕ ??? // Что написать здесь, чтобы условие исчезло?
|    КОНЕЦ)

Давайте рассмотрим рабочие варианты решения этой головоломки.

Решение №1: Использование булевой логики и "ИНАЧЕ ИСТИНА"

Самый лаконичный и изящный способ, предложенный в обсуждении, заключается в использовании литерала ИСТИНА в ветке ИНАЧЕ.

Рассмотрим, как это выглядит в коде:


|    И (ВЫБОР
|        КОГДА втМаршрутный.Фильтр <> ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка)
|           ТОГДА втМаршрутный.Фильтр = РасходнаяНакладная.Контрагент.Ответственный
|        ИНАЧЕ ИСТИНА
|    КОНЕЦ)

Почему это работает?

Здесь вступают в силу законы булевой алгебры. Когда СУБД выполняет запрос, она оценивает условия соединения. Если условие в КОГДА не выполняется (то есть фильтр пустой), управление переходит в ветку ИНАЧЕ.

В этом случае выражение превращается в:

... И ИСТИНА

Согласно логике, выражение Условие И ИСТИНА всегда равно самому Условие. То есть добавление "И ИСТИНА" никак не меняет результат выборки, оно фактически "растворяется", позволяя запросу работать так, будто этого дополнительного фильтра нет.

Решение №2: Преобразование в логическое ИЛИ

Второй способ — отказаться от конструкции ВЫБОР в пользу классических логических операторов И / ИЛИ. Это делает запрос более читаемым с точки зрения стандарта SQL и часто понятнее для последующей поддержки.

Логика следующая: запись нам подходит, если (Фильтр пустой) ИЛИ (Фильтр совпадает с полем таблицы).


|    И (втМаршрутный.Фильтр = ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка)
|       ИЛИ втМаршрутный.Фильтр = РасходнаяНакладная.Контрагент.Ответственный)

Давайте проанализируем этот подход:

  1. Если фильтр пустой, первая часть условия (Фильтр = ПустаяСсылка) возвращает ИСТИНА. Поскольку используется оператор ИЛИ, всё выражение становится истинным, и вторая часть (сравнение ответственных) уже не важна. Связь устанавливается.
  2. Если фильтр заполнен, первая часть ложна. Тогда проверяется вторая часть — равенство ответственных. Связь устанавливается только при совпадении.

Важный аспект: Производительность и планы запросов

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

Использование сложных условий (ВЫБОР или ИЛИ) внутри секции соединения (JOIN ON) может негативно сказаться на скорости выполнения запроса, особенно на больших объемах данных.

Почему это происходит?

  1. Index Seek против Index Scan. Для быстрого соединения таблиц СУБД старается использовать поиск по индексу (Index Seek). Это возможно, когда есть четкое условие равенства (ПолеА = ПолеБ). Когда мы добавляем ИЛИ или ВЫБОР, условие становится "размытым". Оптимизатор SQL-сервера часто не может заранее предсказать, какие строки нужны, и вынужден перебирать таблицу целиком (Scan), проверяя условие для каждой строки.
  2. Непредсказуемость CASE. Большинство оптимизаторов СУБД плохо оценивают селективность (количество ожидаемых строк) для условий, спрятанных внутри CASE. Это может привести к выбору неоптимального алгоритма соединения (например, вложенные циклы вместо хэш-соединения).

Лучшая практика: Динамическое формирование текста запроса

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

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

Рассмотрим алгоритм действий:

  1. Пишем основной текст запроса без спорного условия.
  2. В коде 1С проверяем параметр с помощью ЗначениеЗаполнено().
  3. Если параметр заполнен, мы дописываем (конкатенируем) в текст запроса строку с жестким условием.
  4. Если параметр пуст — ничего не добавляем.

Пример реализации на встроенном языке:


ТекстЗапроса = 
    "ВЫБРАТЬ
    |   ...
    |ИЗ
    |   ВТ_Маршрутный КАК втМаршрутный
    |       ЛЕВОЕ СОЕДИНЕНИЕ Документ.РасходнаяНакладная КАК РасходнаяНакладная
    |       ПО втМаршрутный.ОсновноеПоле = РасходнаяНакладная.ОсновноеПоле";

// Динамически добавляем условие, только если оно реально нужно
Если ЗначениеЗаполнено(ТорговыйПредставительОтбор) Тогда
    ТекстЗапроса = ТекстЗапроса + 
    " И втМаршрутный.ФильтрТорговыйПредставитель = РасходнаяНакладная.Контрагент.Ответственный";
КонецЕсли;

Запрос.Текст = ТекстЗапроса;

Преимущества архитектурного подхода:

Итоги

Давайте подведем итоги выбора метода решения задачи:

  1. ИНАЧЕ ИСТИНА — Отличный вариант для быстрых, разовых запросов или небольших таблиц. Легко пишется, решает проблему синтаксиса.
  2. Логическое ИЛИ — Более стандартизированный вариант, но имеет те же риски производительности, что и первый метод.
  3. Динамическая сборка текста — Самый надежный и профессиональный подход для высоконагруженных систем и отчетов, где важна скорость работы. Исключает проблему "плохого плана запроса".

Используйте метод с ВЫБОР ... ИНАЧЕ ИСТИНА осторожно, понимая, как он работает, но стремитесь к упрощению текста запроса, генерируя его программно там, где это возможно.

← На главную