Как в запросе 1С отобрать элементы, если их табличная часть содержит все значения из списка?

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

В разработке на платформе 1С часто возникает задача: найти элементы одного справочника, у которых табличная часть полностью или частично заполнена определенным набором значений из другого справочника. Например, найти все коммерческие предложения, в которых есть товары "А", "Б" и "В", причем могут быть и другие товары.

Исходный вопрос на форуме звучал так: "Предположим, есть справочник1, есть справочник2. У элемента справочник1 есть тч, состоящая из элементов справочник2. Как написать условие запроса, чтобы отобранный элемент справочник1 содержал в своей тч все значения из переданного в запрос списка значений?".

Эта, на первый взгляд, простая задача имеет важные нюансы. В ходе обсуждения выяснилось, что фразу "содержал все значения" можно трактовать по-разному:

  1. Сценарий "Вхождения": Табличная часть должна содержать все элементы из нашего списка, но может содержать и другие, дополнительные элементы.
  2. Сценарий "Полного соответствия": Табличная часть должна состоять в точности из тех элементов, что есть в нашем списке — ни больше, ни меньше.

Рассмотрим, как решить обе эти задачи с помощью языка запросов 1С.

Решение 1: Сценарий "Вхождения" (содержит все из списка + возможно другие)

Это наиболее частый случай. Нам нужно убедиться, что все искомые элементы присутствуют, а наличие "лишних" записей в табличной части нас не волнует. Классический и правильный подход для этой задачи был предложен в обсуждении и заключается в использовании группировки и условия ИМЕЮЩИЕ.

Проанализируем логику по шагам:

  1. Фильтрация. Сначала из всей табличной части (Справочник1.ТабличнаяЧасть) мы отбираем только те строки, которые в принципе нас интересуют — то есть те, где реквизит со ссылкой на Справочник2 присутствует в нашем списке. Для этого используем оператор В (&СписокЗначений).
  2. Группировка. Затем мы группируем полученные строки по владельцу — по ссылке на Справочник1. В результате для каждого элемента Справочник1 мы получаем группу строк из его табличной части, которые совпали с нашим списком.
  3. Подсчет и сравнение. Это ключевой шаг. Внутри каждой группы мы подсчитываем количество уникальных элементов Справочник2 с помощью агрегатной функции КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...). Если это количество равно размеру нашего исходного списка, значит, мы нашли все, что искали. Сравнение выполняется в секции ИМЕЮЩИЕ.

Посмотрим на пример запроса:

Предположим, у нас есть параметр запроса &СписокЗначений (тип СписокЗначений или Массив) и параметр &РазмерСпискаЗначений, в который мы заранее передаем количество элементов в этом списке.


ВЫБРАТЬ
    ТЧ.Ссылка КАК СсылкаНаСправочник1
ИЗ
    Справочник.Справочник1.ТабличнаяЧасть КАК ТЧ
ГДЕ
    ТЧ.РеквизитСправочник2 В (&СписокЗначений)
СГРУППИРОВАТЬ ПО
    ТЧ.Ссылка
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТЧ.РеквизитСправочник2) = &РазмерСпискаЗначений

Разберем его подробнее:

Важно: в параметр &РазмерСпискаЗначений нужно передавать количество именно уникальных элементов исходного списка, если в нем могут быть дубликаты. Проще всего перед выполнением запроса подготовить массив уникальных значений.

Решение 2: Сценарий "Полного соответствия" (точное совпадение)

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

Для решения этой задачи потребуется более сложный запрос с двумя проверками в условии ИМЕЮЩИЕ.

Логика здесь двойная:

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

Посмотрим на пример запроса:


ВЫБРАТЬ
    ТЧ.Ссылка КАК СсылкаНаСправочник1
ИЗ
    Справочник.Справочник1.ТабличнаяЧасть КАК ТЧ
СГРУППИРОВАТЬ ПО
    ТЧ.Ссылка
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(ТЧ.РеквизитСправочник2) = &РазмерСпискаЗначений
    И МИНИМУМ(ВЫБОР
            КОГДА ТЧ.РеквизитСправочник2 В (&СписокЗначений)
                ТОГДА 1
            ИНАЧЕ 0
        КОНЕЦ) = 1

Как это работает:

В этом запросе мы убрали условие ГДЕ и проверяем все уже после группировки.

Таким образом, комбинация этих двух условий гарантирует, что в табличной части ровно столько строк, сколько элементов в списке, и все эти строки без исключения присутствуют в этом списке.

Заключение

Мы рассмотрели два подхода к решению задачи отбора по содержимому табличной части. Выбор конкретного решения зависит от бизнес-требований.

Стоит также помнить о дубликатах. Если в бизнес-задаче важно, чтобы и количество дублей в табличной части совпадало с количеством дублей в исходном списке (например, в списке [ТоварА, ТоварА, ТоварБ], и в ТЧ должно быть ровно два "ТовараА" и один "ТоварБ"), то задача значительно усложняется. Такие проблемы обычно решаются через временные таблицы с нумерацией строк и их последующим сложным соединением, что выходит за рамки стандартных группировок.

← На главную