Как получить запросом документы только с определенным списком номенклатур в 1С

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

В практике разработчика 1С часто возникает задача отбора документов по сложному условию в их табличных частях. Типичный пример: нужно найти все заказы, в которых продается только «Товар А» и «Товар Б». Если в заказе появляется «Товар В», такой документ должен быть исключен из выборки. Более того, иногда требуется найти только те документы, где присутствуют все позиции из списка одновременно, и ничего больше.

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

Метод 1: Исключение документов с «посторонней» номенклатурой

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

Для начала создадим таблицу документов, в которых присутствует номенклатура, отличная от выбранной:


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

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


// Шаг 2: Получаем чистый список
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ЗаказКлиентаТовары.Ссылка КАК Ссылка
ИЗ
    Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ЗаказыСЛишним КАК ВТ_ЗаказыСЛишним
ПО ЗаказКлиентаТовары.Ссылка = ВТ_ЗаказыСЛишним.Ссылка
ГДЕ
    ЗаказКлиентаТовары.Номенклатура В (&СписокНоменклатуры)
    И ВТ_ЗаказыСЛишним.Ссылка ЕСТЬ NULL

Использование ЛЕВОЕ СОЕДИНЕНИЕ и проверки на NULL — это классический прием в 1С для реализации вычитания множеств. Он работает быстрее, чем использование оператора В (ВЫБРАТЬ...) с отрицанием, особенно на больших объемах данных.

Метод 2: Сравнение количества уникальных позиций (Реляционное деление)

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

Разберем по шагам реализацию этого подхода:

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

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


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

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

В данном коде мы используем агрегатную функцию МАКСИМУМ внутри блока ИМЕЮЩИЕ. Это позволяет нам проверить наличие хотя бы одной «плохой» строки в рамках всей группы строк одного документа. Если максимум равен 0 — значит, плохих строк нет.

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

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

Комбинированный подход для сложных задач

Рассмотрим ситуацию, когда нам нужно найти документы, где только выбранные товары, но не обязательно все сразу (например, только Товар А, или только Товар Б, или оба вместе, но без Товара В). В этом случае мы упрощаем условие из Метода 2, убирая проверку на равенство эталонному количеству:


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

Здесь условие КОЛИЧЕСТВО > 0 необходимо для того, чтобы отсечь пустые документы (если бизнес-логика позволяет их существование), так как формально в пустом документе тоже нет «лишней» номенклатуры.

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

← На главную