Как в запросе 1С выбрать документы, содержащие все товары из списка?

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

В процессе работы с 1С часто возникает задача отобрать документы, например, «Заказы покупателя», которые содержат не просто какой-либо товар из списка, а полный и обязательный набор этих товаров. Стандартная конструкция запроса ГДЕ Номенклатура В (&СписокНоменклатуры) здесь не подходит, так как она сработает по логике «ИЛИ» и вернет все заказы, где есть хотя бы одна позиция из списка.

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

Решение 1: Использование группировки и условия ИМЕЮЩИЕ

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

Разберем алгоритм по шагам:

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

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


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

СГРУППИРОВАТЬ ПО
    Т.Ссылка

ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Т.Номенклатура) = &СписокКоличество

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

Решение 2: Использование временных таблиц

Этот подход выполняет ту же задачу, но может быть более читаемым и структурированным, особенно в составе больших и сложных запросов. Идея состоит в том, чтобы сначала поместить наш список искомых товаров во временную таблицу, а затем соединить с ней табличную часть документов.

Рассмотрим по шагам:

  1. Создание временной таблицы. В первом пакете запроса мы создаем временную таблицу (например, ВТСписокНоменклатуры) и помещаем в нее номенклатуру из переданного параметра (например, &ТаблицаЗначенийНоменклатуры).
  2. Соединение таблиц. Во втором пакете запроса мы используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN) табличной части документов ЗаказПокупателя.Товары с нашей временной таблицей. Соединение производится по полю номенклатуры. В результате этого соединения в выборке останутся только те строки заказов, номенклатура в которых присутствует в нашем списке.
  3. Группировка и проверка. Дальнейшие шаги полностью аналогичны первому решению: группируем результат по ссылке на документ и в условии ИМЕЮЩИЕ проверяем, что количество найденных уникальных позиций равно общему количеству искомых товаров.

Пример реализации с временной таблицей:


// Пакет 1: Помещаем список номенклатуры во временную таблицу
ВЫБРАТЬ
    НоменклатураТаблица.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТСписокНоменклатуры
ИЗ
    &ТаблицаЗначенийНоменклатуры КАК НоменклатураТаблица
;

////////////////////////////////////////////////////////////////////////////////
// Пакет 2: Основной запрос для отбора документов
ВЫБРАТЬ
    ЗаказПокупателяТовары.Ссылка КАК Заказ
ИЗ
    Документ.ЗаказПокупателя.Товары КАК ЗаказПокупателяТовары
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТСписокНоменклатуры
        ПО ЗаказПокупателяТовары.Номенклатура = ВТСписокНоменклатуры.Номенклатура

СГРУППИРОВАТЬ ПО
    ЗаказПокупателяТовары.Ссылка

ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказПокупателяТовары.Номенклатура) = &КоличествоНоменклатуры

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

Особый случай: почему старый отчет перестал работать? Загадка режима совместимости

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

На первый взгляд, такая конструкция нелогична. Условие Поле = "А" И Поле = "Б" для одной и той же записи никогда не может быть истинным, так как поле не может одновременно иметь два разных значения. Так почему же это работало раньше?

Выясним причину. Ответ кроется в поведении Системы Компоновки Данных (СКД) и режиме совместимости платформы 1С.

Решение, которое нашел автор, — установить для конфигурации режим совместимости с версией 8.3.10 — является рабочим, но временным обходным маневром. Оно заставляет платформу эмулировать поведение старой версии, но при этом лишает вас возможности использовать новые функции и оптимизации более свежих версий платформы.

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

← На главную