Почему возникает ошибка несовместимости типов в условиях запроса с ТИПЗНАЧЕНИЯ и как её исправить?

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

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

Разберем детально, почему запрос, успешно работавший на старых релизах платформы, начинает падать с ошибкой, и рассмотрим правильные варианты обхода этой проблемы.

Посмотрим на классический пример проблемного запроса:


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

И код установки параметров во встроенном языке:


Запрос.УстановитьПараметр("ЕстьУсловие", ТипыДокументов <> Неопределено);
Запрос.УстановитьПараметр("Типы", ТипыДокументов);

Если переменная ТипыДокументов равна значению Неопределено, флаг &ЕстьУсловие принимает значение Ложь. На старых версиях платформы оптимизатор запросов просто транслировал это выражение в WHERE 1=1. Однако на более свежих версиях платформы без режима совместимости такой запрос вызывает исключение.

Причина изменения поведения платформы

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

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

Способ 1. Передача пустого типизированного массива (быстрое исправление)

Если требуется сохранить текущую структуру запросов без масштабной переработки кода, убедимся, что в параметр &Типы всегда передается коллекция правильного типа (даже если она пустая):


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

Когда в параметр передан пустой массив, платформа определяет тип параметра как коллекцию и успешно проходит этап валидации.

Способ 2. Динамическое формирование текста запроса (рекомендуемый стандарт)

Использование конструкции ВЫБОР КОГДА &Флаг ТОГДА ... ИНАЧЕ ИСТИНА КОНЕЦ является антипаттерном в разработке 1С. Такие конструкции ухудшают читаемость, мешают СУБД строить оптимальные планы запросов (Non-SARGable выражения) и вызывают проблемы с кэшированием планов (Parameter Sniffing).

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


ТекстЗапроса = 
"ВЫБРАТЬ
|   ВТ.Документ КАК Документ
|ИЗ
|   ВременнаяТаблица КАК ВТ";

Если ТипыДокументов <> Неопределено И ТипыДокументов.Количество() > 0 Тогда
    ТекстЗапроса = ТекстЗапроса + "
    |ГДЕ
    |   ТИПЗНАЧЕНИЯ(ВТ.Документ) В (&Типы)";
    Запрос.Текст = ТекстЗапроса;
    Запрос.УстановитьПараметр("Типы", ТипыДокументов);
Иначе
    Запрос.Текст = ТекстЗапроса;
КонецЕсли;

Этот подход гарантирует:

  1. Отсутствие лишних параметров в запросе.
  2. Отсутствие ошибок несоответствия типов.
  3. Построение СУБД максимально эффективного плана выполнения без избыточных проверок.

Способ 3. Использование оператора ССЫЛКА вместо ТИПЗНАЧЕНИЯ

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


ВЫБРАТЬ
    ВТ.Документ КАК Документ
ИЗ
    ВременнаяТаблица КАК ВТ
ГДЕ
    ВТ.Документ ССЫЛКА Документ.АктОбОказанииПроизводственныхУслуг
    ИЛИ ВТ.Документ ССЫЛКА Документ.РеализацияТоваровУслуг

Оператор ССЫЛКА напрямую транслируется в проверку таблицы метаданных СУБД (по полю типа ссылки), что значительно повышает скорость выборки данных по сравнению с вычислением ТИПЗНАЧЕНИЯ в блоке ГДЕ.

← На главную