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