Как найти номенклатуру, соответствующую нескольким дополнительным реквизитам одновременно?

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

При работе с современными конфигурациями 1С, такими как Управление торговлей 11, ERP или Комплексная автоматизация, мы часто сталкиваемся с необходимостью подбора товаров по техническим характеристикам. Эти характеристики обычно хранятся в табличной части ДополнительныеРеквизиты. Основная сложность заключается в том, что стандартный запрос с использованием оператора В в условии ГДЕ работает по логике «ИЛИ». Если мы укажем в параметрах «DDR4» и «16 Гб», система выдаст нам всю номенклатуру, где есть либо DDR4, либо 16 Гб. Наша же задача — найти только те позиции, где присутствуют оба этих свойства одновременно.

Разберем детально, как реализовать логику «И» для произвольного количества свойств и значений, чтобы обеспечить точный поиск номенклатуры.

Метод 1: Группировка и подсчет совпадений (Золотой стандарт)

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

Рассмотрим логику работы этого запроса. Допустим, нам нужно найти оперативную память с тремя параметрами: частота 2133 МГц, объем 16 Гб и тип DDR4. Если мы просто выберем все строки табличной части, подходящие под эти условия, то для одной номенклатуры может найтись от 1 до 3 строк. Нам нужны только те, для которых нашлось ровно 3 строки.

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


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

В данном случае параметр &КоличествоКритериев будет равен 3. Выясним, почему этот метод считается оптимальным:

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

Метод 2: Динамическое построение внутренних соединений

Рассмотрим альтернативный подход, который часто встречается в старых школах разработки. Суть заключается в том, чтобы для каждого искомого свойства присоединять таблицу дополнительных реквизитов заново через ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Поскольку соединение внутреннее, в итоговую выборку попадут только те ссылки, которые есть во всех соединяемых наборах данных.

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


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

Важный нюанс: Этот метод хорошо работает, когда свойств немного (2-3). Однако при увеличении количества условий до 10 и более, количество соединений в запросе может негативно сказаться на скорости выполнения, так как планировщику SQL-запросов будет сложнее построить оптимальный план выполнения.

Особенности работы с типами данных в доп. реквизитах

Выясним важную техническую деталь, упомянутую в обсуждении. Поле Значение в табличной части ДополнительныеРеквизиты имеет составной тип. Это означает, что там могут храниться как ссылки (на справочник ЗначенияСвойствОбъектов), так и числа, строки или даты.

При формировании массива параметров или динамического условия ГДЕ, крайне важно соблюдать типизацию:

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

Метод 3: Использование временных таблиц и последовательного отсеивания

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

Разберем этот процесс по шагам:

  1. Создаем временную таблицу ВТ_Фильтр, куда помещаем все ссылки номенклатуры, обладающие первым свойством.
  2. Следующим пакетом запроса выбираем данные из ВТ_Фильтр, соединяем их с таблицей доп. реквизитов и оставляем только те, у которых есть второе свойство. Результат помещаем в новую временную таблицу (или заменяем старую).
  3. Повторяем итерации для всех параметров.

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

Рекомендации по реализации

Для создания универсального механизма поиска рекомендуем программно формировать текст запроса. В качестве входящего параметра лучше всего использовать ТаблицаЗначений или Массив Структур, где каждая структура содержит поля Свойство и Значение.

Проанализируем примерный алгоритм подготовки запроса на языке 1С:


ТекстУсловий = "";
Количество = СписокПараметров.Количество();

Для Сч = 1 По Количество Цикл
    ТекстУсловий = ТекстУсловий + " (Свойство = &Свойство" + Сч + " И Значение = &Значение" + Сч + ")";
    Если Сч <> Количество Тогда
        ТекстУсловий = ТекстУсловий + " ИЛИ ";
    КонецЕсли;
    Запрос.УстановитьПараметр("Свойство" + Сч, СписокПараметров[Сч-1].Свойство);
    Запрос.УстановитьПараметр("Значение" + Сч, СписокПараметров[Сч-1].Значение);
КонецЦикла;

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

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

← На главную