Как работает конструкция ВЫБОР без секции ИНАЧЕ в запросах 1С?

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

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

Суть проблемы и поведение оператора ВЫБОР

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


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
|    СвязанныеДокументы.Ссылка КАК Ссылка
|ИЗ
|    КритерийОтбора.СвязанныеДокументы(&ЗначениеКритерияОтбора) КАК СвязанныеДокументы
|ГДЕ
|    ВЫБОР
|            КОГДА СвязанныеДокументы.Ссылка ССЫЛКА Задача.ЗадачаИсполнителя
|                ТОГДА СвязанныеДокументы.Ссылка.CRM_Личная
|                ИЛИ СвязанныеДокументы.Ссылка.БизнесПроцесс ССЫЛКА БизнесПроцесс.CRM_БизнесПроцесс
|    КОНЕЦ";

Разберем по шагам, что здесь происходит:

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

Таким образом, пропуск ИНАЧЕ не эквивалентен возврату Ложь на уровне типа данных, но в контексте секции ГДЕ результат оказывается аналогичным — строка отбрасывается.

Проблема разыменования составных полей и производительность

Посмотрим на пример еще внимательнее и выясним причину потенциальных проблем с производительностью. В запросе выполняется обращение через точку к реквизитам Ссылка.CRM_Личная и Ссылка.БизнесПроцесс.

Поскольку поле Ссылка является составным, обращение к его реквизитам через точку без предварительного ограничения заставляет платформу формировать неявные соединения LEFT JOIN со всеми существующими таблицами объектов конфигурации, входящими в этот тип. Это существенно утяжеляет сформированный SQL-запрос.

Кроме того, использование конструкции ВЫБОР внутри секции ГДЕ нарушает принцип SARGability (Search Argument Able): оптимизатор СУБД теряет возможность применить поиск по индексам (Index Seek) и переходит к полному сканированию всей таблицы (Table Scan / Index Scan).

Способ 1. Минимальное исправление с добавлением ИНАЧЕ

Если требуется быстро восстановить работоспособность выборки без кардинальной переработки структуры запроса, достаточно явно вернуть Истина для всех остальных типов ссылок, которые не являются задачами:


ГДЕ
    ВЫБОР
        КОГДА СвязанныеДокументы.Ссылка ССЫЛКА Задача.ЗадачаИсполнителя
            ТОГДА СвязанныеДокументы.Ссылка.CRM_Личная
                ИЛИ СвязанныеДокументы.Ссылка.БизнесПроцесс ССЫЛКА БизнесПроцесс.CRM_БизнесПроцесс
        ИНАЧЕ ИСТИНА
    КОНЕЦ

В этом случае строки, не относящиеся к типу Задача.ЗадачаИсполнителя, получают значение Истина и успешно возвращаются запросом.

Способ 2. Оптимальное решение по стандартам разработки 1С

Проанализируем рекомендуемый подход. Согласно стандартам разработки 1С, в условиях соединения ПО и условиях фильтрации ГДЕ следует избегать использования конструкции ВЫБОР, заменяя её стандартными булевыми операторами (И, ИЛИ, НЕ). При этом составные ссылочные поля перед обращением к их свойствам необходимо явно приводить с помощью функции ВЫРАЗИТЬ.

Перепишем блок условий в соответствии со стандартами платформы:


ГДЕ
    НЕ СвязанныеДокументы.Ссылка ССЫЛКА Задача.ЗадачаИсполнителя
    ИЛИ (ВЫРАЗИТЬ(СвязанныеДокументы.Ссылка КАК Задача.ЗадачаИсполнителя).CRM_Личная
        ИЛИ ВЫРАЗИТЬ(СвязанныеДокументы.Ссылка КАК Задача.ЗадачаИсполнителя).БизнесПроцесс ССЫЛКА БизнесПроцесс.CRM_БизнесПроцесс)

Разберем преимущества этого варианта:

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