При обновлении платформы 1С:Предприятие 8.3 или отключении режима совместимости со старыми версиями разработчики часто сталкиваются с ошибкой: «Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов». Ошибка возникает при выполнении запросов, в которых реализованы универсальные условия с флагами через конструкцию ВЫБОР КОГДА ....
Разберем детально, почему запрос, успешно работавший на старых релизах платформы, начинает падать с ошибкой, и рассмотрим правильные варианты обхода этой проблемы.
Посмотрим на классический пример проблемного запроса:
ВЫБРАТЬ
ВТ.Документ КАК Документ
ИЗ
ВременнаяТаблица КАК ВТ
ГДЕ
ВЫБОР
КОГДА &ЕстьУсловие
ТОГДА ТИПЗНАЧЕНИЯ(ВТ.Документ) В (&Типы)
ИНАЧЕ ИСТИНА
КОНЕЦ
И код установки параметров во встроенном языке:
Запрос.УстановитьПараметр("ЕстьУсловие", ТипыДокументов <> Неопределено);
Запрос.УстановитьПараметр("Типы", ТипыДокументов);
Если переменная ТипыДокументов равна значению Неопределено, флаг &ЕстьУсловие принимает значение Ложь. На старых версиях платформы оптимизатор запросов просто транслировал это выражение в WHERE 1=1. Однако на более свежих версиях платформы без режима совместимости такой запрос вызывает исключение.
Проанализируем механику работы транслятора запросов 1С:
ВЫБОР КОГДА ....ТИПЗНАЧЕНИЯ. Функция ТИПЗНАЧЕНИЯ возвращает специальный системный тип Тип. Операция В (&Типы) требует, чтобы в параметр передавался объект с типом Тип, либо коллекция (массив, список значений), содержащая значения типа Тип. Значение Неопределено несовместимо с этой операцией, что и приводит к ошибке типизации на этапе компиляции запроса.ВЫБОР КОГДА отсекает вычисления на этапе исполнения запроса в СУБД, но не отменяет валидацию типов на сервере 1С.Если требуется сохранить текущую структуру запросов без масштабной переработки кода, убедимся, что в параметр &Типы всегда передается коллекция правильного типа (даже если она пустая):
Если ТипыДокументов = Неопределено Тогда
Запрос.УстановитьПараметр("ЕстьУсловие", Ложь);
Запрос.УстановитьПараметр("Типы", Новый Массив);
Иначе
Запрос.УстановитьПараметр("ЕстьУсловие", Истина);
Запрос.УстановитьПараметр("Типы", ТипыДокументов);
КонецЕсли;
Когда в параметр передан пустой массив, платформа определяет тип параметра как коллекцию и успешно проходит этап валидации.
Использование конструкции ВЫБОР КОГДА &Флаг ТОГДА ... ИНАЧЕ ИСТИНА КОНЕЦ является антипаттерном в разработке 1С. Такие конструкции ухудшают читаемость, мешают СУБД строить оптимальные планы запросов (Non-SARGable выражения) и вызывают проблемы с кэшированием планов (Parameter Sniffing).
Рассмотрим правильный подход на основе динамической сборки условий:
ТекстЗапроса =
"ВЫБРАТЬ
| ВТ.Документ КАК Документ
|ИЗ
| ВременнаяТаблица КАК ВТ";
Если ТипыДокументов <> Неопределено И ТипыДокументов.Количество() > 0 Тогда
ТекстЗапроса = ТекстЗапроса + "
|ГДЕ
| ТИПЗНАЧЕНИЯ(ВТ.Документ) В (&Типы)";
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Типы", ТипыДокументов);
Иначе
Запрос.Текст = ТекстЗапроса;
КонецЕсли;
Этот подход гарантирует:
Если набор проверяемых типов документов известен заранее, предпочтительнее использовать конструкцию ССЫЛКА вместо функции ТИПЗНАЧЕНИЯ:
ВЫБРАТЬ
ВТ.Документ КАК Документ
ИЗ
ВременнаяТаблица КАК ВТ
ГДЕ
ВТ.Документ ССЫЛКА Документ.АктОбОказанииПроизводственныхУслуг
ИЛИ ВТ.Документ ССЫЛКА Документ.РеализацияТоваровУслуг
Оператор ССЫЛКА напрямую транслируется в проверку таблицы метаданных СУБД (по полю типа ссылки), что значительно повышает скорость выборки данных по сравнению с вычислением ТИПЗНАЧЕНИЯ в блоке ГДЕ.