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