При разработке алгоритмов на платформе 1С часто возникает задача отфильтровать данные в запросе по значениям, расположенным в табличной части документа или обработки. Разберем по шагам, как правильно передать колонку табличной части в параметр запроса, какие существуют варианты реализации и на что следует обратить внимание для обеспечения высокой производительности.
Самый простой и лаконичный способ — выгрузить нужную колонку табличной части в массив с помощью метода ВыгрузитьКолонку() и передать полученный массив в параметр запроса. В самом тексте запроса используется условие с оператором В (&Параметр).
Рассмотрим пример реализации данного подхода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказыКлиентов.Номенклатура КАК Номенклатура
|ИЗ
| РегистрНакопления.ЗаказыКлиентов КАК ЗаказыКлиентов
|ГДЕ
| ЗаказыКлиентов.СтатусЗаказа = &СтатусЗаказа
| И ЗаказыКлиентов.Номенклатура В (&МассивНоменклатуры)";
Запрос.УстановитьПараметр("СтатусЗаказа", Ложь);
Запрос.УстановитьПараметр("МассивНоменклатуры", Объект.Резерв.ВыгрузитьКолонку("Номенклатура"));
РезультатЗапроса = Запрос.Выполнить();
Преимущества метода: минимальное количество кода, простота чтения и высокая скорость написания.
Ограничения: если передаваемый массив содержит очень большое количество элементов (более 1000–2000 штук), СУБД (например, MS SQL Server или PostgreSQL) может испытывать сложности с оптимальной компиляцией плана запроса. В SQL-запросе формируется длинный список параметров, что снижает быстродействие.
Если требуется обработать большой объем строк или сопоставить несколько колонок табличной части, оптимальным решением является передача всей табличной части в запрос и помещение ее во временную таблицу. В этом случае мы передаем коллекцию целиком в параметр запроса &Резерв и обрабатываем ее в рамках пакета запросов.
Проанализируем пример использования пакета запросов:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЧ.Номенклатура КАК Номенклатура
|ПОМЕСТИТЬ ВТ_Резерв
|ИЗ
| &Резерв КАК ТЧ
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ЗаказыКлиентов.Номенклатура КАК Номенклатура
|ИЗ
| РегистрНакопления.ЗаказыКлиентов КАК ЗаказыКлиентов
|ГДЕ
| ЗаказыКлиентов.СтатусЗаказа = &СтатусЗаказа
| И ЗаказыКлиентов.Номенклатура В
| (ВЫБРАТЬ
| ВТ.Номенклатура
| ИЗ
| ВТ_Резерв КАК ВТ)";
Запрос.УстановитьПараметр("СтатусЗаказа", Ложь);
Запрос.УстановитьПараметр("Резерв", Объект.Резерв);
РезультатЗапроса = Запрос.Выполнить();
Важно помнить: при передаче табличной части во временную таблицу условия фильтрации строится через вложенную выборку вида Номенклатура В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_Резерв КАК ВТ) или через соединение (ПОЕДИНЕНИЕ).
Для корректной и быстрой работы алгоритмов учитывайте следующие технические особенности платформы 1С:
ДанныеФормыКоллекция напрямую в параметр запроса на сервере нельзя. На сервере необходимо предварительно перенести данные в объект базы данных либо преобразовать коллекцию формы в обычную таблицу значений или массив (например, с помощью метода РеквизитФормыВЗначение()).ТаблицуЗначений, для всех ее колонок обязательно должно быть задано точное ОписаниеТипов. В противном случае платформа выбросит ошибку.ИНДЕКСИРОВАТЬ ПО для ключевых полей, по которым в дальнейшем производятся соединения или фильтрация. Это существенно ускоряет выборку на стороне СУБД.РегистрНакопления.ЗаказыКлиентов.Остатки), передавать фильтрацию по номенклатуре следует непосредственно в параметры самой виртуальной таблицы, а не в блок ГДЕ. Использование блока ГДЕ для виртуальных таблиц заставляет систему сначала рассчитать итоги по всей базе данных и лишь затем отсечь лишние строки.Выбор конкретного метода зависит от объема обрабатываемых данных: для небольших табличных частей удобнее использовать выгрузку колонки в массив, а для сложных выборок с большими объемами информации — временные таблицы и пакетные запросы.