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