В практике разработки на платформе 1С часто возникает задача: получить скидку или цену из регистра сведений для конкретной номенклатуры. При этом, если скидка не установлена непосредственно на элемент, необходимо взять значение у его родительской группы, если нет у родителя — у «дедушки» и так далее по иерархии.
Сложность заключается в ограничениях языка запросов 1С:
WITH RECURSIVE из T-SQL или PostgreSQL).В ИЕРАРХИИ работает только в секции отбора ГДЕ, и ее нельзя применить в условии соединения таблиц ПО.Рассмотрим основные и наиболее эффективные способы решения этой задачи.
Проанализируем подход, предложенный на форуме. Он заключается в том, чтобы сначала собрать сам элемент и всю цепочку его вышестоящих родителей в массив, а затем передать этот массив в параметр запроса.
Разберем алгоритм по шагам:
Массив.ГДЕ Номенклатура В (&МассивИерархии).Посмотрим на пример кода реализации данного метода:
// Формируем массив родительских элементов
МассивИерархии = Новый Массив;
ТекущийЭлемент = ВыбраннаяНоменклатура;
Пока ЗначениеЗаполнено(ТекущийЭлемент) Цикл
МассивИерархии.Добавить(ТекущийЭлемент);
ТекущийЭлемент = ТекущийЭлемент.Родитель;
КонецЦикла;
// Выполняем запрос к регистру сведений
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Скидки.Номенклатура КАК Номенклатура,
| Скидки.ПроцентСкидки КАК ПроцентСкидки
|ИЗ
| РегистрСведений.СкидкиНоменклатуры.СрезПоследних(&Период, Номенклатура В (&МассивИерархии)) КАК Скидки";
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("МассивИерархии", МассивИерархии);
Выборка = Запрос.Выполнить().Выбрать();
После выполнения запроса остается обойти массив иерархии в исходном порядке (от элемента к родителям) и сопоставить с полученной выборкой из регистра, взяв первое попавшееся значение.
Если необходимо получить скидки сразу для списка товаров исключительно средствами запроса, можно использовать соединение таблицы номенклатуры с регистром сведений по уровням родительской иерархии.
Рассмотрим пример запроса, рассчитанного на ограниченную глубину иерархии (например, до 3 уровней):
ВЫБРАТЬ
Спр.Ссылка КАК Номенклатура,
ВЫБОР
КОГДА СкидкаЭлемента.ПроцентСкидки ЕСТЬ НЕ NULL И СкидкаЭлемента.ПроцентСкидки <> 0
ТОГДА СкидкаЭлемента.ПроцентСкидки
КОГДА СкидкаРодителя1.ПроцентСкидки ЕСТЬ НЕ NULL И СкидкаРодителя1.ПроцентСкидки <> 0
ТОГДА СкидкаРодителя1.ПроцентСкидки
КОГДА СкидкаРодителя2.ПроцентСкидки ЕСТЬ НЕ NULL И СкидкаРодителя2.ПроцентСкидки <> 0
ТОГДА СкидкаРодителя2.ПроцентСкидки
ИНАЧЕ 0
КОНЕЦ КАК ПроцентСкидки
ИЗ
Справочник.Номенклатура КАК Спр
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СкидкиНоменклатуры.СрезПоследних(&Период, ) КАК СкидкаЭлемента
ПО Спр.Ссылка = СкидкаЭлемента.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СкидкиНоменклатуры.СрезПоследних(&Период, ) КАК СкидкаРодителя1
ПО Спр.Родитель = СкидкаРодителя1.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СкидкиНоменклатуры.СрезПоследних(&Период, ) КАК СкидкаРодителя2
ПО Спр.Родитель.Родитель = СкидкаРодителя2.Номенклатура
ГДЕ
Спр.Ссылка = &Номенклатура
Важно: этот способ требует заранее знать или программно формировать максимальную глубину дерева справочника Номенклатура.
Если задача решается в рамках построения отчета, рекурсивный обход иерархии лучше всего доверить СКД. В механизме компоновки данных настраиваются связи наборов данных, где набор связывается сам с собой по полю Родитель. СКД автоматически выполнит рекурсивное подтягивание скидок по иерархии от верхних групп к подчиненным элементам.
В (&Массив)).ВЫБОР КОГДА.