Как реализовать отбор документов по номенклатуре из табличной части в списке или журнале 1С?

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

При работе в среде 1С:Предприятие часто возникает задача: в форме списка или журнале документов (например, «Поступление товаров и услуг») быстро отобрать только те документы, в которых присутствует определенная номенклатура — для этого подойдёт панель быстрых фильтров для списков 1С. Поскольку номенклатура хранится в табличной части, а стандартные отборы динамического списка работают только по реквизитам шапки, эта задача требует особого технического подхода. Если решать её неоптимально, можно столкнуться с резким падением производительности СУБД и зависанием системы.

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

---

Способ 1. Получение массива ссылок через запрос (Программный метод)

Рассмотрим самый очевидный способ, который часто выбирают разработчики. Его суть заключается в следующем: мы добавляем на форму списка документов поле выбора номенклатуры. При изменении этого поля мы делаем запрос к табличной части документов, выбираем все документы, где встречается данный товар, выгружаем их в массив и устанавливаем этот массив в качестве отбора для динамического списка.

Разберем этот процесс по шагам. Создадим на форме списка реквизит ОтборТовар с типом ссылки на справочник Номенклатура и вынесем его на форму. Для события ПриИзменении этого поля напишем следующий код:


&НаКлиенте
Процедура ОтборТоварПриИзменении(Элемент)
    УстановитьОтборПоТоваруНаСервере();
КонецПроцедуры

&НаСервере
Процедура УстановитьОтборПоТоваруНаСервере()
    
    // Очищаем предыдущий отбор по ссылке, если он был установлен
    ОбщегоНазначенияКлиентСервер.УдалитьЭлементыОтбораДинамическогоСписка(Список, "Ссылка");
    
    Если ЗначениеЗаполнено(ОтборТовар) Тогда
        
        // Шаг 1. Получаем ссылки на документы, содержащие выбранную номенклатуру
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ РАЗЛИЧНЫЕ
            |	ТабЧасть.Ссылка КАК Ссылка
            |ИЗ
            |	Документ.ПоступлениеТоваровУслуг.Товары КАК ТабЧасть
            |ГДЕ
            |	ТабЧасть.Номенклатура = &Номенклатура";
            
        Запрос.УстановитьПараметр("Номенклатура", ОтборТовар);
        ТаблицаСсылок = Запрос.Выполнить().Выгрузить();
        МассивСсылок = ТаблицаСсылок.ВыгрузитьКолонку("Ссылка");
        
        // Шаг 2. Устанавливаем отбор в динамическом списке по массиву полученных ссылок
        Если МассивСсылок.Количество() > 0 Тогда
            ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
                Список, 
                "Ссылка", 
                МассивСсылок, 
                РежимСравненияВыбораИспользования.ВВыборе
            );
        Иначе
            // Если документов с таким товаром нет, передаем пустой массив, чтобы список очистился
            ПустойМассив = Новый Массив;
            ПустойМассив.Добавить(Документы.ПоступлениеТоваровУслуг.ПустаяСсылка());
            ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
                Список, 
                "Ссылка", 
                ПустойМассив, 
                РежимСравненияВыбораИспользования.ВВыборе
            );
        EndIf;
        
    КонецЕсли;
    
КонецПроцедуры

Важный нюанс и проблемы производительности: Этот метод прост в реализации, однако он таит в себе серьезную опасность при работе в реальных базах данных. Если выбранный товар является популярным (например, упаковочный пакет в рознице) и содержится в десятках тысяч документов, то полученный массив ссылок будет огромным. Передача списка из более чем 1000–5000 элементов в оператор IN (...) SQL-запроса приводит к катастрофическому замедлению работы СУБД, а в некоторых случаях вызывает аварийное завершение работы сервера SQL из-за переполнения параметров — такие проблемы выявляет анализ и оптимизация производительности запросов 1С.

---

Способ 2. Произвольный запрос динамического списка с вложенным запросом

Чтобы избежать передачи тяжелых массивов данных между сервером приложений и СУБД, проанализируем альтернативный вариант — использование возможностей самого динамического списка. Вместо того чтобы выгружать ссылки на клиенте или сервере в массив, мы можем передать в динамический список один-единственный параметр — выбранную номенклатуру, а всю логику фильтрации переложить на СУБД.

Разберем по шагам, как это настроить:

  1. Откроем свойства динамического списка нашей формы (свойство Список) и установим флаг «Произвольный запрос».
  2. В поле «Настройка списка» откроем конструктор запроса и пропишем текст запроса (удобно через консоль запросов и анализатор СКД), используя конструкцию В (ВЫБРАТЬ...) с проверкой на пустое значение параметра:

ВЫБРАТЬ
    ДокументТаблица.Ссылка КАК Ссылка,
    ДокументТаблица.Дата КАК Дата,
    ДокументТаблица.Номер КАК Номер,
    ДокументТаблица.Проведен КАК Проведен,
    ДокументТаблица.СуммаДокумента КАК СуммаДокумента
ИЗ
    Документ.ПоступлениеТоваровУслуг КАК ДокументТаблица
ГДЕ
    (&ОтборНоменклатура = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
        ИЛИ ДокументТаблица.Ссылка В 
            (ВЫБРАТЬ 
                ТЧ.Ссылка 
             ИЗ 
                Документ.ПоступлениеТоваровУслуг.Товары КАК ТЧ 
             ГДЕ 
                ТЧ.Номенклатура = &ОтборНоменклатура))

Теперь при изменении реквизита отбора на форме нам не нужно делать промежуточные запросы в коде. Достаточно просто передать значение параметра в динамический список:


&НаСервере
Процедура УстановитьПараметрДинамическогоСписка()
    ЗначениеПараметра = ?(ЗначениеЗаполнено(ОтборТовар), ОтборТовар, Справочники.Номенклатура.ПустаяСсылка());
    Список.Параметры.УстановитьЗначениеПараметра("ОтборНоменклатура", ЗначениеПараметра);
КонецПроцедуры

При таком подходе СУБД сама строит оптимальный план выполнения запроса, используя внутренние механизмы и индексы табличных частей. Производительность этого решения значительно выше первого варианта.

---

Способ 3. Оптимальная настройка динамического списка через схему компоновки (без дублирования строк)

Если мы попытаемся сделать левое соединение (LEFT JOIN) таблицы документа с таблицей товаров в обычном запросе динамического списка для получения поля отбора, то при просмотре списка строки документов начнут дублироваться (каждая строка документа будет выведена столько раз, сколько различных товаров присутствует в его табличной части). Использование оператора РАЗЛИЧНЫЕ решит проблему дубликатов, но снизит производительность на больших объемах данных.

Правильный профессиональный подход заключается в тонкой настройке Системы компоновки данных (СКД), которая управляет выборкой в динамическом списке:

  1. Перейдем в свойства динамического списка и откроем конструктор запроса (с включенным произвольным запросом).
  2. Сделаем левое соединение основной таблицы документа с его табличной частью товаров.
  3. Важный секрет: Не нужно выводить поле номенклатуры в список выбираемых полей на первой вкладке конструктора запроса! Вместо этого перейдем на вкладку «Компоновка данных».
  4. В окне настроек компоновки данных найдем поле табличной части Товары.Номенклатура и добавим его исключительно в раздел **«Условия»**.

Благодаря этому трюку поле «Номенклатура» появится у пользователя в стандартных настройках отбора («Еще -> Настроить список -> Отбор») — также есть готовое расширение настройки отборов в списках 1С. При обычном открытии формы без установленного отбора СУБД будет выполнять легкий стандартный запрос без каких-либо соединений с табличными частями. Соединение таблиц и фильтрация произойдут только тогда, когда пользователь непосредственно активирует данный отбор. При этом дублирования строк на экране происходить не будет.

---

Способ 4. Встроенный объект платформы «Критерии отбора»

Выясним, как решить задачу с помощью штатного механизма платформы, созданного специально для таких сценариев — объекта метаданных «Критерии отбора» (Selection Criteria).

Рассмотрим, как его настроить в конфигураторе:

  1. В дереве метаданных найдем ветку «Критерии отбора» и добавим новый объект, например, СвязанныеДокументыПоНоменклатуре.
  2. На вкладке «Основные» укажем тип значения — ссылка на справочник Номенклатура.
  3. Перейдем на вкладку «Состав». Здесь платформа выведет список всех табличных частей всех документов вашей конфигурации. Отметим галочками нужные поля, например: Документ.ПоступлениеТоваровУслуг.Товары.Реквизит.Номенклатура, Документ.РеализацияТоваровУслуг.Товары.Реквизит.Номенклатура и т.д.

Преимущества использования критериев отбора:


&НаКлиенте
Процедура ПоказатьДокументыПоТовару(ТоварСсылка)
    ПараметрыОтбора = Новый Структура("Значение", ТоварСсылка);
    ОткрытьФорму("КритерийОтбора.СвязанныеДокументыПоНоменклатуре.ФормаСписка", ПараметрыОтбора);
КонецПроцедуры

---

Способ 5. Денормализация данных (метод служебных реквизитов)

В высоконагруженных типовых конфигурациях 1С (например, в решениях на базе БСП, таких как ЗУП 3.1) разработчики используют метод денормализации данных. Чтобы не обращаться к тяжелым табличным частям при каждом просмотре списка, в шапку документа добавляют специальный служебный строковый реквизит (например, КраткийСоставДокумента).

При записи документа этот реквизит программно заполняется строковым перечислением элементов (например, первыми буквами фамилий сотрудников или ключевыми наименованиями номенклатуры). В форме списка поиск и отбор осуществляются по этому текстовому реквизиту шапки. Это существенно повышает скорость работы интерфейса, однако имеет ограничение по длине строки (как правило, длина ограничивается 100-150 символами, поэтому все элементы табличной части туда могут не поместиться).

---

Способ 6. Использование Полнотекстового поиска (БСП)

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

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

---

Подведем итоги

Мы проанализировали несколько вариантов реализации отбора документов по номенклатуре из табличной части. Для простых и средних баз данных наиболее изящным и быстрым решением является **Способ 3** (настройка динамического списка через вкладку «Условия» в схеме компоновки). Если же требуется осуществлять поиск по множеству различных видов документов одновременно, то наилучшим решением будет использование штатного механизма **«Критерии отбора»** (Способ 4), так как он обеспечивает максимальную производительность на уровне СУБД.

← На главную