Рассмотрим частую, но не самую тривиальную задачу в 1С: как в Системе Компоновки Данных (СКД) найти документы (например, чеки или заказы), в табличной части которых присутствует строго заданный список номенклатуры. Иными словами, нужно проверить, что в табличной части есть весь указанный набор товаров.
Проанализируем ситуацию: почему не сработают обычные пользовательские отборы СКД? Проблема заключается в том, что применение стандартного фильтра по номенклатуре с видом сравнения «В списке» к табличной части документа работает по логике «ИЛИ» относительно строк. Система найдет все документы, где есть хотя бы один элемент из списка. Заставить стандартный отбор искать пересечение всех элементов (логика «И» для разных строк одной табличной части) стандартными средствами интерфейса невозможно. Поэтому нам потребуется программное вмешательство или написание специфического запроса. Разберем по шагам доступные методы.
Задачу проверки на вхождение полного набора элементов (так называемое реляционное деление) выясним, как можно решить с использованием группировки и конструкции ИМЕЮЩИЕ. Это избавит нас от необходимости городить сложные левые соединения.
Для этого в СКД достаточно передать два параметра: сам массив искомой номенклатуры (&СписокНоменклатуры) и число — размер этого массива (&КоличествоЭлементовВНаборе). Логика запроса строится следующим образом:
В.ИМЕЮЩИЕ.Посмотрим на пример такого запроса:
ВЫБРАТЬ
ЗаказКлиентаМИСТовары.Ссылка КАК Ссылка
ИЗ
Документ.ЗаказКлиентаМИС.Товары КАК ЗаказКлиентаМИСТовары
ГДЕ
ЗаказКлиентаМИСТовары.Номенклатура В (&СписокНоменклатуры)
СГРУППИРОВАТЬ ПО
ЗаказКлиентаМИСТовары.Ссылка
ИМЕЮЩИЕ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказКлиентаМИСТовары.Номенклатура) = &КоличествоЭлементовВНаборе
Таким образом, запрос вернет только те документы, в которых количество найденных уникальных совпадений из списка в точности равно размеру искомого набора.
Разберем другой подход. Начиная с платформы версии 8.3.17, появилась удобная возможность передавать менеджер временных таблиц напрямую в СКД. До этого приходилось использовать громоздкие наборы данных - объекты.
Как это работает на практике:
Посмотрим на пример кода инициализации:
// Предполагается, что МенеджерВТ уже содержит нужную таблицу
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(
МакетКомпоновки,
ВнешниеНаборыДанных,
ДанныеРасшифровки,
Истина,
Ложь,
МенеджерВТ // Передаем шестым параметром!
);
Важный нюанс: чтобы СКД правильно поняла типы данных колонок из переданной временной таблицы, в тексте запроса СКД поля нужно обязательно типизировать. Сделаем это с помощью функции ВЫРАЗИТЬ или ЕСТЬNULL. Например: ВЫРАЗИТЬ(ВТ.Номенклатура КАК Справочник.Номенклатура).
На форуме был предложен еще один вариант составления запроса. Проанализируем его логику. Идея состоит в том, чтобы взять исходный набор и левым соединением привязать к нему товары документа, проверяя отсутствие NULL значений.
Пример запроса:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка
ПОМЕСТИТЬ втНабор
ИЗ
Справочник.Номенклатура КАК Номенклатура
{ГДЕ
Номенклатура.Ссылка.* КАК Набор}
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЗаказКлиентаМИСТовары.Ссылка КАК Ссылка,
ЗаказКлиентаМИСТовары.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ втТовары
{ВЫБРАТЬ
Ссылка.*,
Номенклатура.*}
ИЗ
Документ.ЗаказКлиентаМИС.Товары КАК ЗаказКлиентаМИСТовары
ГДЕ
ЗаказКлиентаМИСТовары.Ссылка = &Ссылка
{ГДЕ
ЗаказКлиентаМИСТовары.Номенклатура.*}
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МИНИМУМ(ВЫБОР
КОГДА втТовары.Ссылка ЕСТЬ NULL
ТОГДА ЛОЖЬ
ИНАЧЕ ИСТИНА
КОНЕЦ) КАК ПолныйНабор
ИЗ
втНабор КАК втНабор
ЛЕВОЕ СОЕДИНЕНИЕ втТовары КАК втТовары
ПО (втТовары.Номенклатура = втНабор.Ссылка)
В этом запросе, если агрегатная функция МИНИМУМ возвращает ИСТИНА, это означает, что ни одной строки с NULL не обнаружено, следовательно, все элементы набора присутствуют в документе. Хотя этот вариант выглядит более громоздким по сравнению с конструкцией ИМЕЮЩИЕ, он имеет право на жизнь в специфических условиях построения отчетов, где данные формируются поэтапно во временных таблицах.