Почему в запросе 1С не работает проверка типа документа через ВЫБОР КОГДА и ТИПЗНАЧЕНИЯ?

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

При разработке сложных отчетов или процедур обработки данных часто возникает необходимость наложить опциональный фильтр по типу документа. Типичный подход, который часто выбирают начинающие разработчики, — использование конструкции ВЫБОР КОГДА внутри секции ГДЕ с проверкой флага использования отбора и функции ТИПЗНАЧЕНИЯ.

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

Анализ проблемы: почему конструкция с ТИПЗНАЧЕНИЯ дает сбой

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


ГДЕ
    ВЫБОР
        КОГДА &ИспользоватьОтборВидДокумента
            ТОГДА ТИПЗНАЧЕНИЯ(ВТ.РасходнаяНакладная.Ссылка) = &ВидДокумента
        ИНАЧЕ ИСТИНА
    КОНЕЦ

В коде встроенного языка логика кажется очевидной: если флаг &ИспользоватьОтборВидДокумента равен Ложь, то в параметр &ВидДокумента передается Неопределено, а условие должно автоматически вернуть Истина. Но при выполнении запроса платформа выбрасывает исключение.

Выясним причину ошибки:

  1. Строгая типизация параметров для ТИПЗНАЧЕНИЯ. Оператор ТИПЗНАЧЕНИЯ(...) = &Параметр требует, чтобы в параметр было передано значение строго типа Тип (например, полученное через Тип("ДокументСсылка.РасходнаяНакладная")). Если передать Неопределено, платформа падает с ошибкой несоответствия типов еще на стадии валидации параметров до непосредственного вычисления логики строк.
  2. Отсутствие гарантированного короткого замыкания (Short-Circuit Evaluation) в SQL. СУБД строит план выполнения и оптимизирует предикаты. Выражения внутри CASE WHEN могут анализироваться и вычисляться оптимизатором базы данных независимо от истинности условий в ветках, что делает передачу невалидных типов опасной.
  3. Неявные соединения составного типа. Во временной таблице поле РасходнаяНакладная содержит ссылки разных типов (документы, справочники). Обращение через точку к реквизиту составного типа (ВТ.РасходнаяНакладная.Ссылка) заставляет платформу создавать тяжелые неявные левые соединения со всеми таблицами, входящими в тип.

Вариант решения 1: Использование проверки ССЫЛКА в ветках выбора

Если требуется сохранить единый текст запроса с параметрами-флагами, заменим функцию ТИПЗНАЧЕНИЯ на проверку принадлежности к конкретной таблице с помощью оператора ССЫЛКА. В параметр &ВидДокумента передадим строковый идентификатор или числовой код вида:


ГДЕ
    ВЫБОР
        КОГДА &ВидДокумента = "Реализация"
            ТОГДА ВТ.РасходнаяНакладная ССЫЛКА Документ.РасходнаяНакладная
        ИНАЧЕ ВЫБОР
            КОГДА &ВидДокумента = "Договор"
                ТОГДА ВТ.РасходнаяНакладная ССЫЛКА Справочник.ДоговорыКонтрагентов
            ИНАЧЕ ВЫБОР
                КОГДА &ВидДокумента = "Приложение"
                    ТОГДА ВТ.РасходнаяНакладная ССЫЛКА Документ.МТТ_ПриложениеКДоговору
                ИНАЧЕ ИСТИНА
            КОНЕЦ
        КОНЕЦ
    КОНЕЦ

Обратите внимание: обращение ВТ.РасходнаяНакладная.Ссылка заменено на прямое поле ВТ.РасходнаяНакладная, что исключает лишние неявные соединения.

Вариант решения 2: Фильтрация по строковому литералу

Если в запросе при объединении разнородных таблиц уже формируется текстовая колонка с названием типа документа (например, "Реализация" КАК ВидДокумента), намного проще и производительнее фильтровать результат по этому полю:


ГДЕ
    ВЫБОР
        КОГДА &ИспользоватьОтборВидДокумента
            ТОГДА ВТ.ВидДокумента = &ВидДокумента
        ИНАЧЕ ИСТИНА
    КОНЕЦ

При таком подходе в &ВидДокумента всегда передается строка (например, пустая строка "" при отключенном отборе). Сравнение строк не вызывает ошибок типизации со стороны платформы 1С.

Вариант решения 3: Динамическая сборка текста условий (Рекомендуемый)

Конструкции вида ВЫБОР КОГДА &Параметр ТОГДА Поле = &Значение ИНАЧЕ ИСТИНА КОНЕЦ существенно ухудшают производительность запросов на больших объемах данных, так как СУБД не может эффективно использовать индексы. Оптимальным решением является динамическое формирование секции ГДЕ во встроенном языке 1С.

Разберем пример динамической установки фильтра:


ТекстУсловия = "";
Если ИспользоватьОтборВидДокумента Тогда
    ТекстУсловия = "ГДЕ ВТ.ВидДокумента = &ВидДокумента";
КонецЕсли;

ТекстЗапроса = 
"ВЫБРАТЬ
|   ВТ.РасходнаяНакладная КАК Ссылка,
|   ВТ.Номер КАК Номер,
|   ВТ.Дата КАК Дата,
|   ВТ.ВидДокумента КАК ВидДокумента
|ИЗ
|   ВТ КАК ВТ
|" + ТекстУсловия;

Запрос = Новый Запрос(ТекстЗапроса);
Если ИспользоватьОтборВидДокумента Тогда
    Запрос.УстановитьПараметр("ВидДокумента", ВыбранныйВидДокумента);
КонецЕсли;

Результат = Запрос.Выполнить();

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

  1. Текст SQL-запроса остается чистым и легко читаемым.
  2. СУБД строит оптимальный план выполнения с использованием индексов.
  3. Исключаются любые конфликты непереданных или пустых параметров.
← На главную