Как исключить уже выбранные в документах записи из формы подбора

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Промышленность, строительство и АПК
← На главную

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

Способ 1. Модификация запроса динамического списка

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

Разберем логику построения такого запроса по шагам. Основная идея заключается в использовании механизма ЛЕВОЕ СОЕДИНЕНИЕ между основной таблицей данных и таблицей-исключением. Проанализируем пример реализации:

  1. Сначала мы подготавливаем основную выборку данных (например, остатки материалов).
  2. Затем присоединяем к ней таблицу документа, данные которого нужно исключить.
  3. В условии запроса указываем, что запись из второй таблицы не должна быть найдена.

Посмотрим на пример кода запроса, который можно внедрить в динамический список:


ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    Остатки.Характеристика КАК Характеристика,
    Остатки.КоличествоОстаток КАК Количество
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
    РегистрНакопления.ЗаказыПоставщикам.Остатки(&Дата1, ) КАК Остатки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Остатки.Номенклатура,
    ВТ_Остатки.Характеристика,
    ВТ_Остатки.Количество
ИЗ
    ВТ_Остатки КАК ВТ_Остатки
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаявкаМенеджера.Товары КАК ИсключаемыеТовары
    ПО ВТ_Остатки.Номенклатура = ИсключаемыеТовары.Номенклатура
    И ВТ_Остатки.Характеристика = ИсключаемыеТовары.Характеристика
ГДЕ
    ИсключаемыеТовары.Ссылка ЕСТЬ NULL

В данном случае условие ИсключаемыеТовары.Ссылка ЕСТЬ NULL является ключевым. Оно означает, что в итоговую выборку попадут только те строки из ВТ_Остатки, для которых не нашлось соответствия в табличной части ЗаявкаМенеджера.Товары. Проанализируем ситуацию: если запись уже существует в документе, соединение вернет ссылку, и условие ЕСТЬ NULL не выполнится, следовательно, строка будет скрыта из подбора.

Способ 2. Программная установка отбора через фиксированные настройки

Если форма подбора открывается программно (например, из формы документа), мы можем передать в нее список исключений в виде массива ссылок. Это удобно, если список исключаемых объектов динамически меняется в зависимости от контекста текущего документа. Рассмотрим, как это реализовать с использованием НастройкиКомпоновкиДанных.

Рассмотрим алгоритм действий:

  1. Сформируем массив ссылок номенклатуры, которую нужно исключить.
  2. Создадим объект НастройкиКомпоновкиДанных.
  3. Добавим элемент отбора с видом сравнения НеВСписке (или НеРавно, если ссылка одна).
  4. Передадим эти настройки в параметры открытия формы.

Пример программного кода для реализации этого метода:


// Собираем массив уже выбранных позиций из текущего документа
МассивИсключений = Объект.Товары.ВыгрузитьКолонку("Номенклатура");

НастройкиКомпоновки = Новый НастройкиКомпоновкиДанных;
ЭлементОтбора = НастройкиКомпоновки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));

ЭлементОтбора.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных("Ссылка"); // Или другое поле, по которому фильтруем
ЭлементОтбора.ВидСравнения   = ВидСравненияКомпоновкиДанных.НеВСписке;
ЭлементОтбора.Использование  = Истина;
ЭлементОтбора.ПравоеЗначение = МассивИсключений;

ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ФиксированныеНастройки", НастройкиКомпоновки);
ПараметрыФормы.Вставить("РежимВыбора", Истина);

ОткрытьФорму("Справочник.Номенклатура.ФормаВыбора", ПараметрыФормы, Элемент);

Этот метод хорош тем, что он не требует жесткого изменения текста запроса в метаданных и позволяет гибко управлять фильтрацией "на лету". Однако помните, что при очень большом количестве исключаемых элементов (тысячи и более) передача огромного массива в параметры запроса может негативно сказаться на производительности СУБД.

Способ 3. Динамическая замена текста запроса

В некоторых сложных конфигурациях (например, в решениях на базе ERP) используется механизм формирования текста запроса путем строковых замен. Выясним причину использования такого подхода: он позволяет вставлять условия ГДЕ только тогда, когда заполнены соответствующие фильтры на форме подбора. Рассмотрим, как можно добавить исключение в такой "конструктор".

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


ТекстЗапроса = "ВЫБРАТЬ ... ГДЕ Истина @УсловиеИсключения@";

Если НужноИсключить Тогда
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "@УсловиеИсключения@", 
        " И НЕ Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ Документ.ЗаказМенеджера.Товары)");
КонецЕсли;

Хотя такой метод кажется простым, он менее предпочтителен, чем ЛЕВОЕ СОЕДИНЕНИЕ, так как конструкция НЕ В (ВЫБРАТЬ...) в некоторых СУБД (например, в PostgreSQL) может работать медленнее. Рекомендуем по возможности использовать временные таблицы для хранения списка исключений и связывать их через соединения.

Рекомендации по оптимизации производительности

Разберем несколько важных моментов, которые помогут сделать подбор быстрым:

Таким образом, мы рассмотрели основные технические решения задачи исключения записей из подбора. Выбор конкретного метода зависит от архитектуры вашего решения: для статических правил лучше подходит модификация запроса динамического списка, а для гибких пользовательских фильтров — программная установка ФиксированныеНастройки.

← На главную