Почему возникает ошибка "Неверные параметры в операции сравнения" в Построителе отчета при использовании дат?

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

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

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

Разбор ситуации: где прячется ошибка?

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


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

При вызове метода ПостроительОтчета.Вывести(ТабличныйДокумент) система выбрасывает исключение. Проблема заключается в том, что в поле &ДатаНач или &ДатаКон передается не примитивный тип Дата, а объект типа Граница. Выясним причину, почему это становится критичным именно для построителя.

Техническое различие между Построителем отчета и СКД

Для понимания сути проблемы проанализируем, как работают эти два механизма:

  1. Система компоновки данных (СКД): Это современный и «умный» механизм. Если вы передаете в параметр СКД объект типа Граница, система автоматически анализирует контекст. Если в тексте запроса этот параметр сравнивается с полем типа Дата, СКД самостоятельно извлекает значение даты из объекта Граница и подставляет его в SQL-запрос. Это называется неявным приведением типов.
  2. Построитель отчета: Это более старая технология (наследие версии 8.0/8.1). Построитель работает гораздо «жестче» и ближе к чистому SQL. Он не умеет самостоятельно преобразовывать сложные объекты платформы (такие как Граница или МоментВремени) в примитивные типы внутри секции ГДЕ или в условиях связи. Когда построитель видит оператор МЕЖДУ, он ожидает с обеих сторон значения идентичных типов. Попытка сравнить Дата (из реквизита документа) и Граница (из параметра) приводит к конфликту на уровне парсера запроса.

Что такое тип "Граница" и почему он конфликтует?

Объект Граница в 1С используется для того, чтобы точно определить момент времени, включая или исключая секунду границы. Он содержит два свойства:

В языке SQL, на котором «общается» СУБД, типа Граница не существует. Существует только DATETIME. Когда вы используете Границу в параметрах виртуальной таблицы (первый и второй параметры), платформа 1С сама обрабатывает этот объект и корректно формирует SQL-запрос для получения итогов. Однако, когда вы используете тот же параметр в секции ГДЕ для сравнения с обычным полем даты, построитель не понимает, как превратить сложный объект в дату, и выдает ошибку о несовместимости.

Варианты решения проблемы

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

Способ 1: Приведение типов параметров в коде

Это самый простой и правильный путь. Перед тем как передать параметры в ПостроительОтчета, необходимо убедиться, что они имеют тип Дата. Если у вас в интерфейсе пользователь выбирает период, который система возвращает как Границу, преобразуйте её принудительно.

Проанализируем пример кода:


// Предположим, ПараметрПериод - это Граница
Если ТипЗнч(ДатаНач) = Тип("Граница") Тогда
    ПостроительОтчета.Параметры.Вставить("ДатаНач", ДатаНач.Значение);
Иначе
    ПостроительОтчета.Параметры.Вставить("ДатаНач", ДатаНач);
КонецЕсли;

Если ТипЗнч(ДатаКон) = Тип("Граница") Тогда
    ПостроительОтчета.Параметры.Вставить("ДатаКон", ДатаКон.Значение);
Иначе
    ПостроительОтчета.Параметры.Вставить("ДатаКон", ДатаКон);
КонецЕсли;

Использование свойства .Значение объекта Граница возвращает чистую дату, которую ПостроительОтчета легко воспримет в любом операторе сравнения.

Способ 2: Использование функции ВЫРАЗИТЬ в запросе

Иногда ошибка возникает из-за того, что поле ЗаказПокупателя имеет составной тип. В этом случае обращение через точку к реквизиту Дата может сбивать построитель с толку, так как не у всех типов в составе может быть этот реквизит. Чтобы обезопасить запрос, используйте явное приведение типа в самом тексте запроса:


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

Важно: этот способ поможет только в том случае, если в параметрах &ДатаНач и &ДатаКон уже переданы даты, а не границы. Если там останутся границы, ошибка не исчезнет.

Способ 3: Проверка на NULL

Хотя автор темы отметил, что проверка на NULL не помогла, в общем случае при обращении к реквизитам через точку в виртуальных таблицах это является хорошим тоном. Если ЗаказПокупателя по какой-то причине не заполнен (хотя в оборотах это редкость), результат обращения к его дате будет NULL, что тоже может вызвать ошибку сравнения.

Пример правильного написания условия с защитой:


ГДЕ
    ЕСТЬNULL(ДополнительнаяСебестоимостьТоваровОбороты.ЗаказПокупателя.Дата, ДАТАВРЕМЯ(1,1,1)) МЕЖДУ &ДатаНач И &ДатаКон

Подведем итоги

Выяснив причину, мы видим, что ПостроительОтчета требует строгого соблюдения типов данных. Главные правила при работе с ним таковы:

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

← На главную