При работе с типовыми конфигурациями 1С, такими как ERP, Управление торговлей или Комплексная автоматизация, программисты часто сталкиваются с необходимостью отобрать объекты (например, номенклатуру) по нескольким дополнительным реквизитам. Дополнительные реквизиты хранятся в табличной части ДополнительныеРеквизиты, и попытка написать простое условие ГДЕ с оператором И для разных свойств приводит к тому, что запрос возвращает пустой результат. Это происходит потому, что одна строка табличной части не может содержать одновременно два разных свойства.
В этой статье мы рассмотрим несколько эффективных способов решения этой задачи: от использования классических соединений до работы с механизмами компоновки данных.
Разберем типичную ситуацию. Нам нужно найти номенклатуру, у которой «Цвет» — «Красный» И «Размер» — «44». Если мы напишем запрос следующим образом:
ВЫБРАТЬ
Номенклатура.Ссылка
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
ГДЕ
(ДопРеквизиты.Свойство = &СвойствоЦвет И ДопРеквизиты.Значение = &ЗначениеКрасный)
И (ДопРеквизиты.Свойство = &СвойствоРазмер И ДопРеквизиты.Значение = &Значение44)
Система будет искать одну строку в табличной части, которая бы удовлетворяла обоим условиям. Но в одной строке может быть только одно свойство. Следовательно, условие никогда не выполнится. Чтобы решить задачу, нам нужно проверить наличие разных строк, относящихся к одному и тому же объекту (ссылке).
Это самый наглядный и часто используемый метод. Мы выбираем ссылку из справочника и последовательно присоединяем к ней таблицу дополнительных реквизитов столько раз, сколько условий нам нужно проверить. Каждое новое ВНУТРЕННЕЕ СОЕДИНЕНИЕ отсекает те объекты, у которых нет соответствующего реквизита.
Рассмотрим пример кода для двух свойств:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты1
ПО Номенклатура.Ссылка = ДопРеквизиты1.Ссылка
И ДопРеквизиты1.Свойство = &Свойство1
И ДопРеквизиты1.Значение = &Значение1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты2
ПО Номенклатура.Ссылка = ДопРеквизиты2.Ссылка
И ДопРеквизиты2.Свойство = &Свойство2
И ДопРеквизиты2.Значение = &Значение2
Проанализируем этот подход: он работает быстро на небольшом количестве свойств, но если условий станет 6 или 10, запрос станет громоздким, а нагрузка на СУБД возрастет из-за большого количества соединений.
Этот метод считается более «элегантным» и часто более производительным. Мы выбираем все строки, которые соответствуют любому из наших условий (через ИЛИ), а затем группируем результат по ссылке и оставляем только те объекты, у которых количество найденных строк равно количеству наших условий.
Рассмотрим реализацию этого метода:
ВЫБРАТЬ
ДопРеквизиты.Ссылка КАК Ссылка
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
ГДЕ
(ДопРеквизиты.Свойство = &Свойство1 И ДопРеквизиты.Значение = &Значение1)
ИЛИ (ДопРеквизиты.Свойство = &Свойство2 И ДопРеквизиты.Значение = &Значение2)
ИЛИ (ДопРеквизиты.Свойство = &Свойство3 И ДопРеквизиты.Значение = &Значение3)
СГРУППИРОВАТЬ ПО
ДопРеквизиты.Ссылка
ИМЕЮЩИЕ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДопРеквизиты.Свойство) = 3
Важный момент: в условии ИМЕЮЩИЕ мы проверяем, что нашлось именно 3 разных свойства. Если в конфигурации допущена ошибка и у одного объекта дважды указано одно и то же свойство с одинаковым значением, оператор РАЗЛИЧНЫЕ внутри КОЛИЧЕСТВО поможет избежать ложноположительных срабатываний.
Если логика отбора сложная (например, часть свойств должна проверяться на равенство, а часть — на вхождение в список), удобно использовать временные таблицы (МенеджерВременныхТаблиц). Мы можем отобрать подходящие ссылки по первому свойству во временную таблицу ВТ_Свойство1, затем из нее отобрать данные по второму свойству в ВТ_Свойство2 и так далее.
Пример построения цепочки фильтров:
ВЫБРАТЬ
ДопРеквизиты.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_Фильтр
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
ГДЕ
ДопРеквизиты.Свойство = &Свойство1 И ДопРеквизиты.Значение = &Значение1;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ДопРеквизиты.Ссылка КАК Ссылка
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Фильтр КАК ВТ_Фильтр
ПО ДопРеквизиты.Ссылка = ВТ_Фильтр.Ссылка
ГДЕ
ДопРеквизиты.Свойство = &Свойство2 И ДопРеквизиты.Значение = &Значение2
Для создания отчетов наиболее правильным решением будет использование механизма Характеристик в Системе компоновки данных (СКД). Это позволяет пользователю выбирать дополнительные реквизиты прямо в дереве полей, как если бы они были обычными реквизитами объекта.
Выполним следующие шаги для настройки:
СправочникСсылка.НоменклатураДополнительныеРеквизитыИСведенияДополнительныеРеквизитыПосле этой настройки в консоли отчетов или в конструкторе запроса мы сможем обращаться к полям через точку, например: Номенклатура.[Цвет]. Платформа самостоятельно сформирует оптимальный SQL-запрос с левыми соединениями для каждого выбранного поля.
При работе с большими базами данных (десятки тысяч позиций номенклатуры) следует учитывать несколько нюансов:
Значение в табличной части имеет составной тип. Чтобы ускорить работу запроса, рекомендуется использовать функцию ВЫРАЗИТЬ(ДопРеквизиты.Значение КАК Справочник.ЗначенияСвойствОбъектов), если вы знаете, что реквизит является ссылочным.Свойство. Это делает отборы достаточно быстрыми.УправлениеСвойствами в вашей конфигурации. В Библиотеке стандартных подсистем есть готовые функции, такие как УправлениеСвойствами.СформироватьЗапросДляЗначенийСвойств(), которые могут автоматизировать построение сложных запросов.Подводя итог, можно сказать, что выбор метода зависит от контекста. Для быстрого разового запроса в коде отлично подойдет Способ 2 (с группировкой), а для сложных пользовательских отчетов в интерфейсе — Способ 4 (характеристики СКД). Мы проанализировали основные подходы и теперь можем эффективно комбинировать их для решения любых задач автоматизации на платформе 1С.