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