Развернуть дерево спецификаций быстро

Программирование - Практика программирования

Спецификации быстро дерево

18
Подход, позволяющий развернуть составы нескольких изделий минимальным количеством запросов.

Суть метода

  Метод заключается в параллельном получении составов различных изделий по уровням дерева и помещение результата в кэш. Таким образом, к базе данных выполняется n-запросов, где <= Максимальная уровень глубины изделия.

Особенности метода

  • алгоритм позволяет получить составы в том случае, если не используются номенклатурные узлы;
  • в исходных комплектующих в полях Номенклатура, ХарактеристикаНоменклатуры должны быть значения типа СправочникСсылка.Номенклатура и СправочникСсылка.ХарактеристикиНоменклатуры соответственно, в противном случае там будет null;
  • не использует спецификации, явно указанные в исходных комплектующих (не стоит галка Использовать вид воспроизводства);
  • основные спецификации номенклатуры получаются на дату актуальных движений(параметр Период не указан);
  • используется алгоритм определения наиболее подходящих спецификаций подобно процедуре общего модуля УправлениеПроизводством.ОпределитьСпецификациюПоУмолчанию().

Описание алгоритма

  1. Сначала наполняется кэш исходных комплектующих спецификаций в процедуре ЗаполнитьКэшСпецификацийРекурсивно(). На вход поступает массив спецификаций изделий, которые необходимо развернуть, КэшСпецификаций - соответствие, которое нужно создать до вызова процедуры;
    1. Внутри выполняется получение исходных комплектующих для данного набора спецификаций. Полученные таблицы для каждой спецификации складываются в соответствие Ключ - Спецификация номенклатуры, Значение - Таблица исходных комплектующих, где для каждой строки определена основная спецификация номенклатуры. Функция ПолучитьСоставСпецификаций();
    2. На предыдущем шаге функция возвращает массив различных спецификаций исходных комплектующих и отправляет его в функцию ПолучитьСоставСпецификаций() еще раз;
    3. Цикл прекращается когда функция не возвратит ни одного элемента.
  2. Имея заполненный кэш спецификаций строим дерево состава изделия процедурой ПостроитьДеревоСпецификацийПоКэшу(). В качестве параметра функция принимает спецификацию номенклатуры, для которой нужно построить дерево состава;

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

Обработка-пример демонстрирует скорость работы данного подхода. Все процедуры алгоритма указаны в модуле обработке.

Тестировалось на платформах 8.2.13, 8.3.11. Конфигурация УПП 1.3.111.

18

Скачать файлы

Наименование Файл Версия Размер
Развернуть дерево спецификаций быстро
.epf 54,40Kb
23.10.18
2
.epf 2018-10-25 54,40Kb 2 Скачать

См. также

Комментарии
Избранное Подписка Сортировка: Древо
2. Rustig 1021 24.10.18 19:01 Сейчас в теме
(0) молодцы! молодцы, что используете кэширование, хеш-таблицы, рекурсию - все это стандартные методы ускорения работы алгоритмов.
молодцы, что не заморочились одним большим запросом для получения дерева. такие и подобные задачи как раз так и решаются.
разработчики, берите на заметку.
3. Red_Devil 158 25.10.18 16:24 Сейчас в теме
{ВнешняяОбработка.ПостроитьДеревоСпецификаций_кэш.МодульОбъекта(589)}: Ошибка при вызове метода контекста (Выполнить)
РезультатЗапроса = Запрос.Выполнить();
по причине:
{(15, 87)}: Поле не найдено "ОриентировочныйСрокПоставки"
ЕСТЬNULL(ВЫРАЗИТЬ(СпецИсходныеКомплектующие.Номенклатура КАК Справочник.Номенклатура)<<?>>.ОриентировочныйСрокПоставки, 0) КАК СрокИзготовления,

ОриентировочныйСрокПоставки это типовой реквизит?
4. SITR-utyos 1077 25.10.18 17:00 Сейчас в теме
(3) Боюсь, что нет. Исправил этот момент
Функция теперь выглядит следующим образом:
// Функция заполняет кэш исходных комплектующих указанного перечня спецификаций
//
// Параметры:
//  КэшСпецификаций  - Соответствие - 
//                 <продолжение описания параметра>
//  МассивСпецификаций  - Массив, СписокЗначений - содержит в себе перечень Спецификаций,
// 							для которых необходимо получить исходные комплектующие
//  ВключатьПустые  - Булево - Определяет, необходимо ли фиксировать Спецификации без исходных комплектующих
//
// Возвращаемое значение:
//   Массив   - Массив спецификаций исходных комплектующих. Используется чтобы вызвать эту функцию повторно
//
Функция ПолучитьСоставСпецификаций(КэшСпецификаций, МассивСпецификаций, ВключатьПустые = Ложь) Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	СпецификацииНоменклатуры.Ссылка КАК СпецификацияПродукции,
	|	СпецИсходныеКомплектующие.НомерСтроки КАК НомерСтроки,
	|	ВЫРАЗИТЬ(СпецИсходныеКомплектующие.Номенклатура КАК Справочник.Номенклатура) КАК Номенклатура,
	|	ВЫРАЗИТЬ(СпецИсходныеКомплектующие.Номенклатура КАК Справочник.Номенклатура).ВидВоспроизводства КАК НоменклатураВидВоспроизводства,
	|	ВЫРАЗИТЬ(СпецИсходныеКомплектующие.Номенклатура КАК Справочник.Номенклатура).ВидНоменклатуры КАК НоменклатураВидНоменклатуры,
	|	ВЫРАЗИТЬ(СпецИсходныеКомплектующие.ХарактеристикаНоменклатуры КАК Справочник.ХарактеристикиНоменклатуры) КАК ХарактеристикаНоменклатуры,
	|	СпецИсходныеКомплектующие.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
	|	ВЫБОР
	|		КОГДА СпецИсходныеКомплектующие.Номенклатура ССЫЛКА Справочник.Номенклатура
	|				И СпецИсходныеКомплектующие.ЕдиницаИзмерения <> ЗНАЧЕНИЕ(Справочник.ЕдиницыИзмерения.ПустаяСсылка)
	|			ТОГДА СпецИсходныеКомплектующие.Количество * СпецИсходныеКомплектующие.ЕдиницаИзмерения.Коэффициент / СпецИсходныеКомплектующие.Номенклатура.ЕдиницаХраненияОстатков.Коэффициент
	|		ИНАЧЕ СпецИсходныеКомплектующие.Количество
	|	КОНЕЦ КАК Количество,
	|	ВЫБОР
	|		КОГДА СпецИсходныеКомплектующие.Ссылка ЕСТЬ NULL
	|			ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК СпецификацияПустая
	|ПОМЕСТИТЬ ВТИсходныеКомплектующиеСпц
	|ИЗ
	|	Справочник.СпецификацииНоменклатуры КАК СпецификацииНоменклатуры
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.СпецификацииНоменклатуры.ИсходныеКомплектующие КАК СпецИсходныеКомплектующие
	|		ПО СпецификацииНоменклатуры.Ссылка = СпецИсходныеКомплектующие.Ссылка
	|ГДЕ
	|	СпецификацииНоменклатуры.Ссылка В(&МассивСпецификаций)
	|	И ВЫБОР
	|			КОГДА &ВключатьПустые
	|				ТОГДА ИСТИНА
	|			ИНАЧЕ НЕ СпецИсходныеКомплектующие.Ссылка ЕСТЬ NULL
	|		КОНЕЦ
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ВЫРАЗИТЬ(ВТИсходныеКомплектующиеСпц.Номенклатура КАК Справочник.Номенклатура) КАК Номенклатура,
	|	ВТИсходныеКомплектующиеСпц.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры
	|ПОМЕСТИТЬ ВТНоменклатураХарактеристики
	|ИЗ
	|	ВТИсходныеКомплектующиеСпц КАК ВТИсходныеКомплектующиеСпц
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ
	|	ОсновныеСпецификацииНоменклатурыСрезПоследних.Номенклатура КАК Номенклатура,
	|	ОсновныеСпецификацииНоменклатурыСрезПоследних.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
	|	ОсновныеСпецификацииНоменклатурыСрезПоследних.СпецификацияНоменклатуры КАК СпецификацияНоменклатуры,
	|	3 КАК Приоритет
	|ПОМЕСТИТЬ ВТСпецификации
	|ИЗ
	|	ВТНоменклатураХарактеристики КАК ВТНоменклатураХарактеристики
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ОсновныеСпецификацииНоменклатуры.СрезПоследних(
	|				,
	|				(Номенклатура, ХарактеристикаНоменклатуры) В
	|					(ВЫБРАТЬ
	|						Таблица.Номенклатура,
	|						Таблица.ХарактеристикаНоменклатуры
	|					ИЗ
	|						ВТНоменклатураХарактеристики КАК Таблица)) КАК ОсновныеСпецификацииНоменклатурыСрезПоследних
	|		ПО ВТНоменклатураХарактеристики.Номенклатура = ОсновныеСпецификацииНоменклатурыСрезПоследних.Номенклатура
	|			И ВТНоменклатураХарактеристики.ХарактеристикаНоменклатуры = ОсновныеСпецификацииНоменклатурыСрезПоследних.ХарактеристикаНоменклатуры
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ОсновныеСпецификацииНоменклатурыСрезПоследних.Номенклатура,
	|	ВТНоменклатураХарактеристики.ХарактеристикаНоменклатуры,
	|	ОсновныеСпецификацииНоменклатурыСрезПоследних.СпецификацияНоменклатуры,
	|	4
	|ИЗ
	|	ВТНоменклатураХарактеристики КАК ВТНоменклатураХарактеристики
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ОсновныеСпецификацииНоменклатуры.СрезПоследних(
	|				,
	|				Номенклатура В
	|						(ВЫБРАТЬ
	|							Таблица.Номенклатура
	|						ИЗ
	|							ВТНоменклатураХарактеристики КАК Таблица)
	|					И ХарактеристикаНоменклатуры = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)) КАК ОсновныеСпецификацииНоменклатурыСрезПоследних
	|		ПО ВТНоменклатураХарактеристики.Номенклатура = ОсновныеСпецификацииНоменклатурыСрезПоследних.Номенклатура
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ОсновныеСпецификацииНоменклатурыСрезПоследних.Номенклатура,
	|	ВТНоменклатураХарактеристики.ХарактеристикаНоменклатуры,
	|	ОсновныеСпецификацииНоменклатурыСрезПоследних.СпецификацияНоменклатуры,
	|	5
	|ИЗ
	|	ВТНоменклатураХарактеристики КАК ВТНоменклатураХарактеристики
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ОсновныеСпецификацииНоменклатуры.СрезПоследних(
	|				,
	|				Номенклатура В
	|					(ВЫБРАТЬ
	|						Таблица.Номенклатура
	|					ИЗ
	|						ВТНоменклатураХарактеристики КАК Таблица)) КАК ОсновныеСпецификацииНоменклатурыСрезПоследних
	|		ПО ВТНоменклатураХарактеристики.Номенклатура = ОсновныеСпецификацииНоменклатурыСрезПоследних.Номенклатура
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ
	|	ВТСпецификации.Номенклатура,
	|	ВТСпецификации.ХарактеристикаНоменклатуры,
	|	ВТСпецификации.СпецификацияНоменклатуры
	|ПОМЕСТИТЬ ВТСпецификацииПоУмолчанию
	|ИЗ
	|	ВТСпецификации КАК ВТСпецификации
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
	|			ВТСпецификации.Номенклатура КАК Номенклатура,
	|			ВТСпецификации.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
	|			МИНИМУМ(ВТСпецификации.Приоритет) КАК Приоритет
	|		ИЗ
	|			ВТСпецификации КАК ВТСпецификации
	|		
	|		СГРУППИРОВАТЬ ПО
	|			ВТСпецификации.Номенклатура,
	|			ВТСпецификации.ХарактеристикаНоменклатуры) КАК МинимальныйПриоритет
	|		ПО ВТСпецификации.Номенклатура = МинимальныйПриоритет.Номенклатура
	|			И ВТСпецификации.ХарактеристикаНоменклатуры = МинимальныйПриоритет.ХарактеристикаНоменклатуры
	|			И ВТСпецификации.Приоритет = МинимальныйПриоритет.Приоритет
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ
	|	ВТИсходныеКомплектующиеСпц.СпецификацияПродукции КАК СпецификацияПродукции,
	|	ВТИсходныеКомплектующиеСпц.НомерСтроки,
	|	ВТИсходныеКомплектующиеСпц.Номенклатура,
	|	ВТИсходныеКомплектующиеСпц.НоменклатураВидВоспроизводства,
	|	ВТИсходныеКомплектующиеСпц.НоменклатураВидНоменклатуры,
	|	ВТИсходныеКомплектующиеСпц.ХарактеристикаНоменклатуры,
	|	ВТИсходныеКомплектующиеСпц.ЕдиницаИзмерения,
	|	ВТИсходныеКомплектующиеСпц.Количество,
	|	ВТИсходныеКомплектующиеСпц.СпецификацияПустая,
	|	ВТСпецификацииПоУмолчанию.СпецификацияНоменклатуры,
	|	ВЫБОР
	|		КОГДА ВТИсходныеКомплектующиеСпц.СпецификацияПродукции = ВТСпецификацииПоУмолчанию.СпецификацияНоменклатуры
	|			ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК ЗацикливаниеСпецификации,
	|	ЕСТЬNULL(СпецВыходныеИзделия.ТочкаМаршрута.Подразделение, ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)) КАК ЦехИзготовитель,
	|	СпецВыходныеИзделия.ТочкаМаршрута КАК ТочкаМаршрута
	|ИЗ
	|	ВТИсходныеКомплектующиеСпц КАК ВТИсходныеКомплектующиеСпц
	|		ЛЕВОЕ СОЕДИНЕНИЕ ВТСпецификацииПоУмолчанию КАК ВТСпецификацииПоУмолчанию
	|			ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.СпецификацииНоменклатуры.ВыходныеИзделия КАК СпецВыходныеИзделия
	|			ПО ВТСпецификацииПоУмолчанию.СпецификацияНоменклатуры = СпецВыходныеИзделия.Ссылка
	|				И ВТСпецификацииПоУмолчанию.Номенклатура = СпецВыходныеИзделия.Номенклатура
	|		ПО ВТИсходныеКомплектующиеСпц.Номенклатура = ВТСпецификацииПоУмолчанию.Номенклатура
	|			И ВТИсходныеКомплектующиеСпц.ХарактеристикаНоменклатуры = ВТСпецификацииПоУмолчанию.ХарактеристикаНоменклатуры
	|
	|УПОРЯДОЧИТЬ ПО
	|	ВТИсходныеКомплектующиеСпц.СпецификацияПродукции,
	|	ВТИсходныеКомплектующиеСпц.НомерСтроки
	|ИТОГИ ПО
	|	СпецификацияПродукции";
	// Устанавливаем параметры
	Запрос.УстановитьПараметр("МассивСпецификаций", МассивСпецификаций);
	Запрос.УстановитьПараметр("ВключатьПустые",		ВключатьПустые);
	РезультатЗапроса = Запрос.Выполнить();
	ВыборкаПоСпецификациям = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	// Создадим таблицу такую же как колонки выборки
	СтруктураТаблицы = Новый ТаблицаЗначений;
	Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл
		Если Колонка.Имя = "СпецификацияПродукции" Тогда
			Продолжить;
		КонецЕсли;
		
		ЗаполнитьЗначенияСвойств(СтруктураТаблицы.Колонки.Добавить(), Колонка);
		
	КонецЦикла;
	
	// Здесь будем хранить различные спецификации исходных комплектующих
	СпецификацииИсходныхКомплектующих = Новый ТаблицаЗначений;
	СпецификацииИсходныхКомплектующих.Колонки.Добавить("СпецификацияНоменклатуры");
	
	// Пройдемся по спецификациям и добавим их в кэш
	Пока ВыборкаПоСпецификациям.Следующий() Цикл
		
		Выборка = ВыборкаПоСпецификациям.Выбрать();
		ИсходныеКомплектующие = СтруктураТаблицы.СкопироватьКолонки();// Создаем Таблицу исходных комплетующих текущей специфиикации. Создаем НОВУЮ таблицу, это очень важно
		Пока Выборка.Следующий() Цикл
			// Спецификация пустая - прерываемся, чтобы таблица исходных комплектующих была пустой
			Если Выборка.СпецификацияПустая Тогда
				Прервать;
			КонецЕсли;
			
		    НоваяСтрока = ИсходныеКомплектующие.Добавить();
		    ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
			
			// Если обнаружено зацикливание - очищаем Спецификацию, чтобы это не обрабатывалось
			Если Выборка.ЗацикливаниеСпецификации Тогда
				Сообщить("Обнаружено зацикливание спецификации на изделие " + Выборка.Номенклатура, СтатусСообщения.Важное);
				НоваяСтрока.СпецификацияНоменклатуры = Справочники.СпецификацииНоменклатуры.ПустаяСсылка();
				Продолжить;
			КонецЕсли;
			
			// Если спецификацию еще не получали - добавим в список
			Если КэшСпецификаций.Получить(Выборка.СпецификацияНоменклатуры) = Неопределено Тогда
				НоваяСтрока = СпецификацииИсходныхКомплектующих.Добавить();
				НоваяСтрока.СпецификацияНоменклатуры = Выборка.СпецификацияНоменклатуры; 
			КонецЕсли;
		КонецЦикла;
		
		// Добавляем в кэш Спецификацию и еще исходные комплектующие в виде ТаблицыЗначений
		КэшСпецификаций.Вставить(ВыборкаПоСпецификациям.СпецификацияПродукции, ИсходныеКомплектующие);
		
	КонецЦикла;
	
	СпецификацииИсходныхКомплектующих.Свернуть("СпецификацияНоменклатуры");
	
	Возврат СпецификацииИсходныхКомплектующих.ВыгрузитьКолонку("СпецификацияНоменклатуры");
	
КонецФункции
Показать
5. yelloo 4 25.10.18 21:11 Сейчас в теме
(4) В ВТ "ВТИсходныеКомплектующиеСпц" и "ВТНоменклатураХарактеристики" в качестве поля "Номенклатура" после "Выразить()" могут быть NULL.
6. SITR-utyos 1077 26.10.18 07:37 Сейчас в теме
(5)
В ВТ "ВТИсходныеКомплектующиеСпц" и "ВТНоменклатураХарактеристики" в качестве поля "Номенклатура" после "Выразить()" могут быть NULL.

Согласен. Добавлено описание в раздел Особенности метода.
Оставьте свое сообщение