При разработке отчетов на платформе 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда один и тот же запрос успешно выполняется в Консоли запросов или в Системе компоновки данных (СКД), но выдает критическую ошибку при использовании ПостроительОтчета. Одной из самых коварных ошибок является сообщение: «Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов».
В этой статье мы подробно разберем, почему возникает эта проблема, чем ПостроительОтчета отличается от современных механизмов вывода данных и как правильно подготовить параметры запроса, чтобы избежать конфликтов типов данных.
Рассмотрим типичный сценарий. Программист пишет запрос к виртуальной таблице оборотов, где пытается отфильтровать данные по дате конкретного документа, обращаясь к нему через точку. Код выглядит примерно так:
ВЫБРАТЬ
ДополнительнаяСебестоимостьТоваровОбороты.ЗаказПокупателя,
ДополнительнаяСебестоимостьТоваровОбороты.ЗаказПокупателя.Дата КАК ДатаЗаказа
ИЗ
РегистрНакопления.ДополнительнаяСебестоимостьТоваров.Обороты(&ДатаНач, &ДатаКон) КАК ДополнительнаяСебестоимостьТоваровОбороты
ГДЕ
ДополнительнаяСебестоимостьТоваровОбороты.ЗаказПокупателя.Дата МЕЖДУ &ДатаНач И &ДатаКон
При вызове метода ПостроительОтчета.Вывести(ТабличныйДокумент) система выбрасывает исключение. Проблема заключается в том, что в поле &ДатаНач или &ДатаКон передается не примитивный тип Дата, а объект типа Граница. Выясним причину, почему это становится критичным именно для построителя.
Для понимания сути проблемы проанализируем, как работают эти два механизма:
Граница, система автоматически анализирует контекст. Если в тексте запроса этот параметр сравнивается с полем типа Дата, СКД самостоятельно извлекает значение даты из объекта Граница и подставляет его в SQL-запрос. Это называется неявным приведением типов.Граница или МоментВремени) в примитивные типы внутри секции ГДЕ или в условиях связи. Когда построитель видит оператор МЕЖДУ, он ожидает с обеих сторон значения идентичных типов. Попытка сравнить Дата (из реквизита документа) и Граница (из параметра) приводит к конфликту на уровне парсера запроса.Объект Граница в 1С используется для того, чтобы точно определить момент времени, включая или исключая секунду границы. Он содержит два свойства:
Значение — непосредственно дата и время.ВидГраницы — перечисление (Включая или Исключая).В языке SQL, на котором «общается» СУБД, типа Граница не существует. Существует только DATETIME. Когда вы используете Границу в параметрах виртуальной таблицы (первый и второй параметры), платформа 1С сама обрабатывает этот объект и корректно формирует SQL-запрос для получения итогов. Однако, когда вы используете тот же параметр в секции ГДЕ для сравнения с обычным полем даты, построитель не понимает, как превратить сложный объект в дату, и выдает ошибку о несовместимости.
Рассмотрим по шагам, как можно исправить эту ошибку и сделать код надежным.
Это самый простой и правильный путь. Перед тем как передать параметры в ПостроительОтчета, необходимо убедиться, что они имеют тип Дата. Если у вас в интерфейсе пользователь выбирает период, который система возвращает как Границу, преобразуйте её принудительно.
Проанализируем пример кода:
// Предположим, ПараметрПериод - это Граница
Если ТипЗнч(ДатаНач) = Тип("Граница") Тогда
ПостроительОтчета.Параметры.Вставить("ДатаНач", ДатаНач.Значение);
Иначе
ПостроительОтчета.Параметры.Вставить("ДатаНач", ДатаНач);
КонецЕсли;
Если ТипЗнч(ДатаКон) = Тип("Граница") Тогда
ПостроительОтчета.Параметры.Вставить("ДатаКон", ДатаКон.Значение);
Иначе
ПостроительОтчета.Параметры.Вставить("ДатаКон", ДатаКон);
КонецЕсли;
Использование свойства .Значение объекта Граница возвращает чистую дату, которую ПостроительОтчета легко воспримет в любом операторе сравнения.
Иногда ошибка возникает из-за того, что поле ЗаказПокупателя имеет составной тип. В этом случае обращение через точку к реквизиту Дата может сбивать построитель с толку, так как не у всех типов в составе может быть этот реквизит. Чтобы обезопасить запрос, используйте явное приведение типа в самом тексте запроса:
ГДЕ
ВЫРАЗИТЬ(ДополнительнаяСебестоимостьТоваровОбороты.ЗаказПокупателя КАК Документ.ЗаказПокупателя).Дата МЕЖДУ &ДатаНач И &ДатаКон
Важно: этот способ поможет только в том случае, если в параметрах &ДатаНач и &ДатаКон уже переданы даты, а не границы. Если там останутся границы, ошибка не исчезнет.
Хотя автор темы отметил, что проверка на NULL не помогла, в общем случае при обращении к реквизитам через точку в виртуальных таблицах это является хорошим тоном. Если ЗаказПокупателя по какой-то причине не заполнен (хотя в оборотах это редкость), результат обращения к его дате будет NULL, что тоже может вызвать ошибку сравнения.
Пример правильного написания условия с защитой:
ГДЕ
ЕСТЬNULL(ДополнительнаяСебестоимостьТоваровОбороты.ЗаказПокупателя.Дата, ДАТАВРЕМЯ(1,1,1)) МЕЖДУ &ДатаНач И &ДатаКон
Выяснив причину, мы видим, что ПостроительОтчета требует строгого соблюдения типов данных. Главные правила при работе с ним таковы:
ГДЕ.Границу только в параметрах виртуальных таблиц (там, где это предусмотрено логикой получения остатков и оборотов).ПостроительОтчета.Параметры.ПостроительОтчета не обладает интеллектом СКД и требует «ручной» подготовки данных.Следуя этим рекомендациям, вы избавитесь от загадочных ошибок сравнения и обеспечите стабильную работу ваших отчетов.