Как реализовать отбор в динамическом списке по реквизитам подчиненного справочника без дублирования строк?

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

Разработка интерфейсов на платформе 1С часто сталкивается с задачей отображения списка объектов (например, Контрагентов), которые нужно отфильтровать по данным подчиненных сущностей (например, Договоров). Сложность заключается в том, что связь между ними — «один ко многим»: у одного контрагента может быть несколько десятков договоров. Если мы просто добавим ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) в запрос динамического списка, мы получим дублирование записей основного объекта столько раз, сколько подчиненных записей найдено в базе.

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

Метод 1. Использование оператора В (IN) и подзапроса

Это самый распространенный и надежный способ. Вместо того чтобы соединять таблицы, мы накладываем условие на поле Ссылка основной таблицы, проверяя её наличие в выборке подчиненного справочника. Рассмотрим ситуацию: нам нужно вывести только тех контрагентов, у которых есть хотя бы один договор с определенным типом.

Проанализируем структуру запроса в динамическом списке:


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

Почему это работает: Оператор В в SQL (и в языке запросов 1С) работает как фильтр вхождения. Даже если у контрагента 10 договоров нужного типа, подзапрос вернет ссылку на контрагента, и основная выборка отобразит его ровно один раз. Это исключает дублирование записей в списке, которое неизбежно возникло бы при использовании соединения.

Метод 2. Использование фигурных скобок для гибких отборов {ГДЕ}

Если нам нужно, чтобы пользователь сам мог выбирать типы договоров в стандартном окне «Настроить список», мы должны использовать расширения языка запросов для СКД. Это позволяет динамическому списку «понимать», когда нужно подключать фильтр по подчиненной таблице, а когда — нет.

Рассмотрим пример настройки текста запроса:


ВЫБРАТЬ
    СправочникКонтрагенты.Ссылка,
    СправочникКонтрагенты.Наименование
ИЗ
    Справочник.Контрагенты КАК СправочникКонтрагенты
{ГДЕ
    СправочникКонтрагенты.Ссылка В
        (ВЫБРАТЬ
            Договоры.Владелец
        ИЗ
            Справочник.Договоры КАК Договоры
        ГДЕ
            Договоры.ТипДоговора.* КАК ТипДоговора)}

В этом случае в настройках динамического списка (на вкладке «Отбор») появится доступное поле ТипДоговора. Если пользователь не установит по нему отбор, платформа проигнорирует подзапрос и список будет работать максимально быстро. Как только флажок будет установлен, платформа подставит условие в итоговый SQL-запрос.

Метод 3. Использование оператора СУЩЕСТВУЕТ (EXISTS)

С точки зрения производительности на больших объемах данных (десятки и сотни тысяч записей), оператор СУЩЕСТВУЕТ часто отрабатывает эффективнее, чем В. Это связано с тем, что оптимизатор SQL-сервера прекращает поиск в подчиненной таблице, как только находит первое совпадение.

Пример реализации в тексте запроса:


ВЫБРАТЬ
    Контрагенты.Ссылка
ИЗ
    Справочник.Контрагенты КАК Контрагенты
ГДЕ
    ЕСТЬ (ВЫБРАТЬ 1 
          ИЗ Справочник.Договоры КАК Договоры 
          ГДЕ Договоры.Владелец = Контрагенты.Ссылка 
          И Договоры.ТипДоговора = &Тип)

Здесь мы не выгружаем все ссылки во временную таблицу для сравнения, а проверяем наличие хотя бы одной записи, удовлетворяющей условию связи. Это классический «halal» способ решения задачи (как выразился автор темы), не требующий динамической программной модификации текста запроса.

Метод 4. Механизм Характеристик (через СКД)

Рассмотрим более сложный, но «продвинутый» вариант. Платформа позволяет описывать дополнительные реквизиты объектов через механизм характеристик. Если настроить Справочник.Договоры как источник характеристик для Справочника.Контрагенты, то типы договоров можно будет выбирать в отборах так, будто это реквизиты самого контрагента.

Для этого в конструкторе запроса динамического списка на закладке «Характеристики» нужно указать:

  1. Типы характеристик: Справочник или План видов характеристик, описывающий виды договоров.
  2. Значения характеристик: Справочник Договоры, где поле Владелец соответствует контрагенту, Вид — типу договора, а Значение — самому договору (или признаку его наличия).

Этот метод позволяет пользователю строить сложнейшие фильтры (например: «Показать контрагентов, у которых есть договор типа А, но нет договора типа Б») без написания единой строки кода.

Важные замечания по производительности и настройке

При работе с динамическими списками важно помнить о следующих нюансах:

Резюме

Проанализировав ситуацию, мы выяснили, что оптимальным решением является использование подзапроса в секции ГДЕ. Это гарантирует уникальность записей, позволяет сохранить Основную таблицу списка и дает возможность гибко настраивать отборы через расширения СКД. Выбирайте вариант с оператором В для простоты реализации или ЕСТЬ (EXISTS) для достижения максимальной производительности на крупных проектах.

← На главную