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

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

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

Анализ исходной проблемы и типичной ошибки

Разберем ситуацию: автор попытался использовать конструкцию ГДЕ НЕ СписокПокупок.Товары.Товар В (Подзапрос). На первый взгляд кажется, что это должно вернуть документы без указанных товаров. Однако в 1С такой запрос отработает иначе: он вернет документ, если в его табличной части есть хотя бы одна строка, товар в которой не входит в список. Если в документе десять строк и девять из них содержат товары из «черного списка», а одна — нет, документ все равно попадет в выборку. Это в корне противоречит условию «ни один элемент не входит в список».

Для правильного решения нам нужно использовать логику отсечения или агрегации данных. Рассмотрим по шагам основные подходы.

Решение 1: Метод исключения (двойное отрицание)

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

Выполним следующие шаги:

  1. Создадим временную таблицу со списком «запрещенных» товаров (или получим их из регистра, как в примере автора).
  2. Выберем все уникальные ссылки на документы, в которых есть хотя бы один такой товар.
  3. Выберем все документы и выполним ЛЕВОЕ СОЕДИНЕНИЕ с нашей временной таблицей по ссылке.
  4. Установим фильтр, где ссылка из временной таблицы ЕСТЬ NULL.

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


// Шаг 1: Получаем документы, которые содержат хотя бы один товар из списка
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ТЧ.Ссылка КАК Ссылка
ПОМЕСТИТЬ ДокументыСТоварамиИзСписка
ИЗ
    Документ.СписокПокупок.Товары КАК ТЧ
ГДЕ
    ТЧ.Товар В (&СписокТоваров);

// Шаг 2: Выбираем документы, которые НЕ попали в первую таблицу
ВЫБРАТЬ
    Док.Ссылка КАК Ссылка
ИЗ
    Документ.СписокПокупок КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ ДокументыСТоварамиИзСписка КАК ИсключаемыеДокументы
    ПО Док.Ссылка = ИсключаемыеДокументы.Ссылка
ГДЕ
    ИсключаемыеДокументы.Ссылка ЕСТЬ NULL

Решение 2: Проверка условия «Только элементы из списка» через агрегацию

Выясним причину, по которой задача «только те, что в списке» решается иначе. Нам нужно убедиться, что в документе нет «лишних» строк. Один из самых быстрых способов — сравнить общее количество строк в документе с количеством строк, которые соответствуют нашему списку.

Рассмотрим алгоритм реализации:

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

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


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

Рекомендации по оптимизации: использование оператора СУЩЕСТВУЕТ

Проанализируем ситуацию с производительностью. Использование оператора В с вложенным запросом может замедлять работу СУБД, так как оптимизатор не всегда эффективно строит план выполнения. В 1С для проверки наличия записей часто эффективнее использовать ГДЕ СУЩЕСТВУЕТ (или ГДЕ НЕ СУЩЕСТВУЕТ).

Преимущество СУЩЕСТВУЕТ заключается в том, что СУБД прекращает поиск, как только найдено первое совпадение. Это значительно быстрее полной выгрузки вложенного запроса.


ВЫБРАТЬ
    Док.Ссылка
ИЗ
    Документ.СписокПокупок КАК Док
ГДЕ
    НЕ СУЩЕСТВУЕТ (
        ВЫБРАТЬ 1
        ИЗ Документ.СписокПокупок.Товары КАК ТЧ
        ГДЕ ТЧ.Ссылка = Док.Ссылка
          И ТЧ.Товар В (&СписокТоваров)
    )

Важные технические нюансы

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

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

← На главную