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