Как исправить ошибку «Нельзя сравнивать поля неограниченной длины и поля несовместимых типов» в запросе 1С?

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

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

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

Причина 1: Передача объекта прикладного типа вместо ссылки

Проанализируем типовую ситуацию. В коде инициализируется запрос, в который передается переменная:


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

Если в переменной ЛицевойСчет находится значение типа СправочникОбъект.ЛицевыеСчета, а измерение регистра ЛицевойСчет имеет тип СправочникСсылка.ЛицевыеСчета, возникает конфликт типов.

Объекты прикладных типов (такие как СправочникОбъект, ДокументОбъект, ПланВидовХарактеристикОбъект) существуют исключительно в оперативной памяти сервера 1С. В физических таблицах СУБД хранятся только уникальные идентификаторы (ссылки). При попытке передать объект целиком транслятор запросов 1С не может выполнить сравнение с полем базы данных и генерирует ошибку несовместимости типов.

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

ЗапросПоТабелю.УстановитьПараметр("ЛицевойСчет", ЛицевойСчет.Ссылка);

Свойство Ссылка у ссылочных типов (СправочникСсылка, ДокументСсылка) возвращает само себя. Поэтому конструкция ЗначениеПеременной.Ссылка универсальна: она корректно отработает как в случае, если в переменной передан объект, так и в случае, если там уже хранилась ссылка.

Причина 2: Сравнение полей неограниченной длины

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

Способ решения: ограничим длину строки с помощью функции ВЫРАЗИТЬ непосредственно в тексте запроса:


ВЫБРАТЬ
    Таблица.Данные КАК Данные
ИЗ
    Справочник.Контрагенты КАК Таблица
ГДЕ
    ВЫРАЗИТЬ(Таблица.Комментарий КАК СТРОКА(150)) = &ПараметрКомментарий

Причина 3: Передача значений Неопределено, NULL или некорректных типов

Посмотрим на ситуацию, когда реквизит в базе данных имеет составной тип или ссылочный тип, а в параметр запроса передается Неопределено, NULL или тип, не входящий в состав разрешенных (например, число вместо ссылки). В этом случае СУБД также сообщает о невозможности сравнения несовместимых типов.

Для явного уточнения типа в запросах к полям составного типа применяются следующие конструкции:

  1. Приведение к конкретному ссылочному типу через ВЫРАЗИТЬ(Поле КАК Справочник.ИмяСправочника);
  2. Проверка типа с помощью оператора ССЫЛКА: Таблица.Поле ССЫЛКА Справочник.ЛицевыеСчета;
  3. Использование логической функции ТИПЗНАЧЕНИЯ(Поле) = ТИП(Справочник.ЛицевыеСчета).

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

Рассмотрим еще одну критическую ошибку в исходном запросе. Наложение условия на виртуальную таблицу через секцию ГДЕ приводит к падению производительности:


// Неоптимальный вариант: фильтрация происходит после получения всех записей среза
ИЗ
    РегистрСведений.Льготы.СрезПоследних КАК ЛьготыСрезПоследних
ГДЕ
    ЛьготыСрезПоследних.ЛицевойСчет = &ЛицевойСчет

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

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


ЗапросПоТабелю = Новый Запрос;
ЗапросПоТабелю.Текст = "ВЫБРАТЬ
                       |    ЛьготыСрезПоследних.Процент КАК Процент
                       |ИЗ
                       |    РегистрСведений.Льготы.СрезПоследних(&Период, ЛицевойСчет = &ЛицевойСчет) КАК ЛьготыСрезПоследних";

ЗапросПоТабелю.УстановитьПараметр("Период", ТекущаяДата());
ЗапросПоТабелю.УстановитьПараметр("ЛицевойСчет", ЛицевойСчет.Ссылка);

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

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

← На главную