Как получить иерархическую скидку из регистра сведений в запросе 1С?

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

В практике разработки на платформе 1С часто возникает задача: получить скидку или цену из регистра сведений для конкретной номенклатуры. При этом, если скидка не установлена непосредственно на элемент, необходимо взять значение у его родительской группы, если нет у родителя — у «дедушки» и так далее по иерархии.

Особенности работы с иерархией в запросах 1С

Сложность заключается в ограничениях языка запросов 1С:

  1. В 1С отсутствуют рекурсивные запросы (аналоги WITH RECURSIVE из T-SQL или PostgreSQL).
  2. Конструкция В ИЕРАРХИИ работает только в секции отбора ГДЕ, и ее нельзя применить в условии соединения таблиц ПО.

Рассмотрим основные и наиболее эффективные способы решения этой задачи.

Способ 1. Выгрузка иерархии в массив и выборка запросом (Гибридный метод)

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

Разберем алгоритм по шагам:

  1. В коде 1С в цикле обходим родительские элементы номенклатуры, начиная от самого элемента и поднимаясь до корня справочника. Все ссылки добавляем в Массив.
  2. Передаем полученный массив в запрос к регистру сведений через условие ГДЕ Номенклатура В (&МассивИерархии).
  3. В запросе или при обработке результата выбираем первое найденное значение скидки.

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


// Формируем массив родительских элементов
МассивИерархии = Новый Массив;
ТекущийЭлемент = ВыбраннаяНоменклатура;

Пока ЗначениеЗаполнено(ТекущийЭлемент) Цикл
    МассивИерархии.Добавить(ТекущийЭлемент);
    ТекущийЭлемент = ТекущийЭлемент.Родитель;
КонецЦикла;

// Выполняем запрос к регистру сведений
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Скидки.Номенклатура КАК Номенклатура,
    |	Скидки.ПроцентСкидки КАК ПроцентСкидки
    |ИЗ
    |	РегистрСведений.СкидкиНоменклатуры.СрезПоследних(&Период, Номенклатура В (&МассивИерархии)) КАК Скидки";

Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("МассивИерархии", МассивИерархии);

Выборка = Запрос.Выполнить().Выбрать();

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

Способ 2. Запрос с цепочкой левых соединений

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

Рассмотрим пример запроса, рассчитанного на ограниченную глубину иерархии (например, до 3 уровней):


ВЫБРАТЬ
	Спр.Ссылка КАК Номенклатура,
	ВЫБОР
		КОГДА СкидкаЭлемента.ПроцентСкидки ЕСТЬ НЕ NULL И СкидкаЭлемента.ПроцентСкидки <> 0 
			ТОГДА СкидкаЭлемента.ПроцентСкидки
		КОГДА СкидкаРодителя1.ПроцентСкидки ЕСТЬ НЕ NULL И СкидкаРодителя1.ПроцентСкидки <> 0 
			ТОГДА СкидкаРодителя1.ПроцентСкидки
		КОГДА СкидкаРодителя2.ПроцентСкидки ЕСТЬ НЕ NULL И СкидкаРодителя2.ПроцентСкидки <> 0 
			ТОГДА СкидкаРодителя2.ПроцентСкидки
		ИНАЧЕ 0
	КОНЕЦ КАК ПроцентСкидки
ИЗ
	Справочник.Номенклатура КАК Спр
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СкидкиНоменклатуры.СрезПоследних(&Период, ) КАК СкидкаЭлемента
		ПО Спр.Ссылка = СкидкаЭлемента.Номенклатура
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СкидкиНоменклатуры.СрезПоследних(&Период, ) КАК СкидкаРодителя1
		ПО Спр.Родитель = СкидкаРодителя1.Номенклатура
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СкидкиНоменклатуры.СрезПоследних(&Период, ) КАК СкидкаРодителя2
		ПО Спр.Родитель.Родитель = СкидкаРодителя2.Номенклатура
ГДЕ
	Спр.Ссылка = &Номенклатура

Важно: этот способ требует заранее знать или программно формировать максимальную глубину дерева справочника Номенклатура.

Способ 3. Использование Системы компоновки данных (СКД)

Если задача решается в рамках построения отчета, рекурсивный обход иерархии лучше всего доверить СКД. В механизме компоновки данных настраиваются связи наборов данных, где набор связывается сам с собой по полю Родитель. СКД автоматически выполнит рекурсивное подтягивание скидок по иерархии от верхних групп к подчиненным элементам.

Подведем итоги

  1. Для применения в прикладном коде (в модулях форм или проведения) наиболее универсален гибридный метод (формирование массива родителей и выборка через В (&Массив)).
  2. Для отчетов целесообразно использовать штатные связи наборов данных в СКД.
  3. Если глубина иерархии заранее известна и невелика, можно применять пакетные запросы с динамическим текстом или конструкцией ВЫБОР КОГДА.
← На главную