Почему не работает отбор в Построителе запроса при использовании таблицы значений и как это исправить?

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

Работа с объектом ПостроительЗапроса в 1С часто сопряжена с нюансами, особенно когда в качестве источника данных выступает не готовый текст запроса к базе данных, а программно сформированная ТаблицаЗначений. Одной из наиболее распространенных проблем является ситуация, когда установленные отборы либо игнорируются системой, либо вызывают ошибку "Недопустимый тип сравнения". Проанализируем причины такого поведения и разберем пошагово, как добиться корректной работы фильтров.

Разбор ситуации: Булево значение и ВидСравнения

Рассмотрим типичный сценарий: у нас есть табличная часть документа, которую мы выгружаем в таблицу значений. В ней присутствует колонка "Использовано" с типом Булево. Мы хотим отобрать только те строки, где значение равно Ложь. На первый взгляд, код кажется простым и понятным, но именно здесь начинаются сложности с объектом ОписаниеИсточникаДанных.

Первая ошибка, с которой сталкиваются разработчики — использование неподходящего вида сравнения. Для типа Булево допустимым является только ВидСравнения.Равно или ВидСравнения.НеРавно. Попытка установить ВидСравнения.Содержит приведет к ошибке, так как этот метод предназначен исключительно для строковых данных. Однако, даже при использовании ВидСравнения.Равно, отбор может не срабатывать, пропуская строки со значением Истина. Это происходит из-за того, что ПостроительЗапроса не может однозначно определить тип данных в колонке или ожидает строгого соответствия метаданным.

Шаг 1: Принудительная типизация колонок таблицы значений

Выясним основную причину: когда мы используем метод Выгрузить() для табличной части, 1С старается сохранить типы данных. Но если таблица подвергалась каким-либо преобразованиям или была создана вручную, тип колонки может стать "составным" или вовсе не определиться корректно для ПостроителяЗапроса. Чтобы избежать этого, рекомендуется принудительно описывать типы колонок перед передачей в построитель.

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


// Выгружаем ТЧ
ТаблицаДанных = ДокументОбъект.Услуги.Выгрузить();

// Если есть сомнения в типизации, создаем описание типов
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Булево"));
ОписаниеТипаБулево = Новый ОписаниеТипов(МассивТипов);

// Принудительно устанавливаем тип для колонки
ТаблицаДанных.Колонки.Использовано.ТипЗначения = ОписаниеТипаБулево;

// Наполняем данными, если колонка была добавлена вручную
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
    Если СтрокаТЗ.Использовано = Неопределено Тогда
        СтрокаТЗ.Использовано = Ложь;
    КонецЕсли;
КонецЦикла;

Шаг 2: Правильная инициализация объекта ОписаниеИсточникаДанных

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


Построитель = Новый ПостроительЗапроса;
Источник = Новый ОписаниеИсточникаДанных(ТаблицаДанных);

// Важно: можно явно указать поля, чтобы построитель точно их "увидел"
Источник.Поля.Использовано.ПутьКДанным = "Использовано";
Построитель.ИсточникДанных = Источник;

// Обязательно вызываем заполнение настроек перед добавлением отбора
Построитель.ЗаполнитьНастройки();

Метод ЗаполнитьНастройки() заставляет построитель проанализировать структуру ИсточникДанных и создать доступные поля для отбора, порядка и группировок. Если этого не сделать, добавление отбора через Построитель.Отбор.Добавить() может работать нестабильно.

Шаг 3: Настройка отбора и порядок свойств

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


ИмяПоля = "Использовано";
ЭлементОтбора = Построитель.Отбор[ИмяПоля];
Если ЭлементОтбора = Неопределено Тогда
    ЭлементОтбора = Построитель.Отбор.Добавить(ИмяПоля);
КонецЕсли;

ЭлементОтбора.ВидСравнения = ВидСравнения.Равно;
ЭлементОтбора.Значение = Ложь;
ЭлементОтбора.Использование = Истина;

Важный нюанс: если вы используете Булево, убедитесь, что в таблице значений нет NULL. ПостроительЗапроса воспринимает NULL как отдельное состояние, которое не равно ни Истина, ни Ложь. Если в вашей таблице есть пустые значения, отбор Равно Ложь их просто проигнорирует.

Шаг 4: Использование индексов для стабильности

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

ТаблицаДанных.Индексы.Добавить("Использовано");

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

Итоговый пример надежного кода

Соберем все рекомендации в единый блок кода, который минимизирует риск возникновения ошибок:


// 1. Подготовка данных
ТЧ_Данные = ДокументОбъект.Услуги.Выгрузить();
ТЧ_Данные.Индексы.Добавить("Использовано");

// 2. Настройка построителя
Построитель = Новый ПостроительЗапроса;
ОписаниеИсточника = Новый ОписаниеИсточникаДанных(ТЧ_Данные);
Построитель.ИсточникДанных = ОписаниеИсточника;

// 3. Инициализация полей
Построитель.ЗаполнитьНастройки();

// 4. Установка фильтра
ПолеОтбора = Построитель.Отбор.Использовано;
ПолеОтбора.ВидСравнения = ВидСравнения.Равно;
ПолеОтбора.Значение = Ложь;
ПолеОтбора.Использование = Истина;

// 5. Выполнение и получение результата
Построитель.Выполнить();
ТаблицаРезультат = Построитель.Результат.Выгрузить();

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

← На главную