Сложности работы с иерархическими справочниками

29.12.23

Разработка - Математика и алгоритмы

В статье представлен алгоритм поиска родителя нулевого уровня для элементов иерархического справочника.

Иерархические справочники достаточно распространенные объекты во всех типовых решениях 1С. Они позволяют разделить хозяйственные операции компании на отдельные элементы, сохранив при этом привязку к главному родителю, что очень удобно для анализа.

В качестве примера приведу справочник "Подразделения". Мы можем разными документами перемещать номенклатуру между отделами, но по основному узлу всегда увидим, что предмет не покидал пределы структурного подразделения.

Однако в этой статье речь пойдет не о преимуществах иерархических справочников, как раз наоборот - о недостатках. И одним из таких минусов является сложность соединения двух таблиц в запросе. На рисунке ниже показан пример связи по полю "Подразделение".

ВЫБРАТЬ
	ВТ_Документы.Подразделение,
	ВТ_Документы.Документ,
	ВТ_Сертификаты.Сертификат
ИЗ
	ВТ_Документы КАК ВТ_Документы
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Сертификаты КАК ВТ_Сертификаты
		ПО ВТ_Документы.Подразделение = ВТ_Сертификаты.Подразделение

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

Именно эта проблема сподвигла меня написать статью и поделиться опытом решения.

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

ВЫБОР
	КОГДА ВТ.Подразделение = &ПодразделениеИерархия
		ТОГДА ВТ.Подразделение
	КОГДА ВТ.Подразделение В ИЕРАРХИИ (&ПодразделениеИерархия)
		ТОГДА &ПодразделениеИерархия
	ИНАЧЕ ВТ.Подразделение
КОНЕЦ КАК Подразделение

Эту операцию нужно проделать во всех таблицах запроса.

ВЫБРАТЬ
	ВЫБОР
		КОГДА ВТ.Подразделение = &ПодразделениеИерархия
			ТОГДА ВТ.Подразделение
		КОГДА ВТ.Подразделение В ИЕРАРХИИ (&ПодразделениеИерархия)
			ТОГДА &ПодразделениеИерархия
		ИНАЧЕ ВТ.Подразделение
	КОНЕЦ КАК Подразделение,
	ВТ.Документ
ПОМЕСТИТЬ ВТ_Документы
ИЗ
	&ТаблицаПараметр1 КАК ВТ
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВЫБОР
		КОГДА ВТ.Подразделение = &ПодразделениеИерархия
			ТОГДА ВТ.Подразделение
		КОГДА ВТ.Подразделение В ИЕРАРХИИ (&ПодразделениеИерархия)
			ТОГДА &ПодразделениеИерархия
		ИНАЧЕ ВТ.Подразделение
	КОНЕЦ КАК Подразделение,
	ВТ.Сертификат
ПОМЕСТИТЬ ВТ_Сертификаты
ИЗ
	&ТаблицаПараметр2 КАК ВТ

В итоге мы получаем вполне рабочий запрос.

ВЫБРАТЬ
	ВЫБОР
		КОГДА ВТ.Подразделение = &ПодразделениеИерархия
			ТОГДА ВТ.Подразделение
		КОГДА ВТ.Подразделение В ИЕРАРХИИ (&ПодразделениеИерархия)
			ТОГДА &ПодразделениеИерархия
		ИНАЧЕ ВТ.Подразделение
	КОНЕЦ КАК Подразделение,
	ВТ.Документ
ПОМЕСТИТЬ ВТ_Документы
ИЗ
	&ТаблицаПараметр1 КАК ВТ
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВЫБОР
		КОГДА ВТ.Подразделение = &ПодразделениеИерархия
			ТОГДА ВТ.Подразделение
		КОГДА ВТ.Подразделение В ИЕРАРХИИ (&ПодразделениеИерархия)
			ТОГДА &ПодразделениеИерархия
		ИНАЧЕ ВТ.Подразделение
	КОНЕЦ КАК Подразделение,
	ВТ.Сертификат
ПОМЕСТИТЬ ВТ_Сертификаты
ИЗ
	&ТаблицаПараметр2 КАК ВТ
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВТ_Документы.Подразделение,
	ВТ_Документы.Документ,
	ВТ_Сертификаты.Сертификат
ИЗ
	ВТ_Документы КАК ВТ_Документы
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Сертификаты КАК ВТ_Сертификаты
		ПО ВТ_Документы.Подразделение = ВТ_Сертификаты.Подразделение

Обработчик вычисления родителя для параметра &ПодразделениеИерархия можно вынести в общий модуль. Один из вариантов алгоритма выглядит так:

Если ЗначениеЗаполнено(СсылкаНаСправочник) Тогда
	МетаданныеСправочника = СсылкаНаСправочник.Метаданные();
		
	МаксЧисло = 0;
	Кеш = Новый Соответствие;
		
	Если МетаданныеСправочника.Иерархический = Истина Тогда
		Для Сч = 0 По 100 Цикл
			МаксЧисло = Макс(Сч, МаксЧисло);
				
			Если Сч = 0 Тогда
				Кеш.Вставить(Сч, СсылкаНаСправочник);
			Иначе
				Результат = Кеш.Получить(Сч - 1);
					
				Если Результат <> Неопределено Тогда
					Если ЗначениеЗаполнено(Результат.Родитель) Тогда
						Кеш.Вставить(Сч, Результат.Родитель);
					Иначе
						Прервать;
					КонецЕсли;
				Иначе
					Прервать;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
	Иначе
		Кеш.Вставить(0, СсылкаНаСправочник);
	КонецЕсли;
		
	Результат = Кеш.Получить(МаксЧисло);
КонецЕсли;

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

На самом деле, способов решения задачки существует много. Здесь представлен один из рабочих вариантов. 

иерархия справочник родитель иерархический справочник родитель справочника

См. также

Математика и алгоритмы Программист Платформа 1C v8.2 Конфигурации 1cv8 Россия Абонемент ($m)

На написание данной работы меня вдохновила работа @glassman «Переход на ClickHouse для анализа метрик». Автор анализирует большой объем данных, много миллионов строк, и убедительно доказывает, что ClickHouse справляется лучше PostgreSQL. Я же покажу как можно сократить объем данных в 49.9 раз при этом: 1. Сохранить значения локальных экстремумов 2. Отклонения от реальных значений имеют наперед заданную допустимую погрешность.

1 стартмани

30.01.2024    3154    stopa85    12    

38

Математика и алгоритмы Бесплатно (free)

Разработка алгоритма, построенного на модели симплекс-метода, для нахождения оптимального раскроя.

19.10.2023    7541    user1959478    51    

36

Математика и алгоритмы Разное Платформа 1С v8.3 Конфигурации 1cv8 Россия Абонемент ($m)

Расширение (+ обработка) представляют собою математический тренажер. Ваш ребенок сможет проверить свои знание на математические вычисление до 100.

2 стартмани

29.09.2023    3101    maksa2005    8    

26

Математика и алгоритмы Инструментарий разработчика Программист Платформа 1С v8.3 Мобильная платформа Россия Абонемент ($m)

Что ж... лучше поздно, чем никогда. Подсистема 1С для работы с регулярными выражениями: разбор выражения, проверка на соответствие шаблону, поиск вхождений в тексте.

1 стартмани

09.06.2023    10893    7    SpaceOfMyHead    18    

61

Математика и алгоритмы Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Три задачи - три идеи - три решения. Мало кода, много смысла. Мини-статья.

03.04.2023    4353    RustIG    9    

25

Механизмы платформы 1С Математика и алгоритмы Программист Платформа 1С v8.3 Россия Бесплатно (free)

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

23.11.2022    3517    gzharkoj    14    

25

Математика и алгоритмы Программист Платформа 1С v8.3 Россия Абонемент ($m)

Обычно под распределением понимают определение сумм пропорционально коэффициентам. Предлагаю включить сюда также распределение по порядку (FIFO, LIFO) и повысить уровень размерности до 2-х. 1-ое означает, что распределение может быть не только пропорциональным, но и по порядку, а 2-ое - это вариант реализации матричного распределения: по строкам и столбцам. Возможно вас заинтересует также необычное решение этой задачи через создание DSL на базе реализации текучего интерфейса

1 стартмани

21.03.2022    9038    7    kalyaka    11    

44
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. ImHunter 327 29.12.23 12:12 Сейчас в теме
Мне кажется, если есть возможность, то лучше явно прописывать такого родителя. Написать так, чтобы это автоматически писалось.
И тогда 99% заморочек исчезнет. И добавится 50% по производительности.
3. user1647484 9 29.12.23 13:40 Сейчас в теме
(1) этот как раз для того 1% случаев, когда явно указать справочник невозможно. Например, в документе указано одно подразделение, а при заполнении табличной части требуется подтягивать данные из регистра. И если информацию занесли и указали смежное подразделение, то запрос с параметром В ИЕРАРХИИ (&Подразделение) ничего не выберет. Система не поймет такое условие. А в отчетах всегда лучше указывать параметр явно. 😊😉😉😉
2. prikhodkosergey 29.12.23 12:43 Сейчас в теме
Не уверен, но, КМК, расчет родитель лучше сделать так

Функция ОпределитьРодителяВерхнегоУровня(СсылкаНаСправочник) Экспорт 
	РодительВерхнегоУровня = Неопределено;
	Если ЗначениеЗаполнено(СсылкаНаСправочник) Тогда
		МетаданныеСправочника = СсылкаНаСправочник.Метаданные();
		РодительВерхнегоУровня = СсылкаНаСправочник;
		Если МетаданныеСправочника.Иерархический = Истина Тогда
			Запрос = Новый Запрос;
			Запрос.Текст = СтрШаблон("
				|ВЫБРАТЬ
				|	Объекты.Ссылка КАК Ссылка
				|ИЗ
				|	%1 КАК Объекты
				|ГДЕ
				|	Объекты.Ссылка = &Ссылка
				|ИТОГИ ПО
				|	Ссылка ТОЛЬКО ИЕРАРХИЯ
				|", МетаданныеСправочника.ПолноеИмя());
			Запрос.УстановитьПараметр("Ссылка", СсылкаНаСправочник);
			РодительВерхнегоУровня = Запрос.Выполнить().Выгрузить(
				ОбходРезультатаЗапроса.Прямой)[0].Ссылка;
		КонецЕсли;
	КонецЕсли;	                       
	Возврат РодительВерхнегоУровня;
КонецФункции
Показать
4. user1647484 9 29.12.23 14:05 Сейчас в теме
(2) да, запросом даже более читаемо. Но вместо выгрузки, я предпочитаю использовать обход результата. Он выгружает весь список, а нам нужен всего один виток цикла, чтобы выбрать первый элемент.
5. prikhodkosergey 29.12.23 15:22 Сейчас в теме
(4)
Он выгружает весь список, а нам нужен всего один виток цикла


А разницы, КМК, если верить этому, нет. И там и там полностью в память читается.
6. lvictor58 137 07.01.24 02:37 Сейчас в теме
Я может чего-то не до конца прошариваяю, но разве родитель у элементов верхнего уровня не равен НЕОПРЕДЕЛЕНО?
7. prikhodkosergey 09.01.24 10:52 Сейчас в теме
(6) Есть задачи, когда необходимо получить группу или элемент вышестоящий, т.е. не всю иерархию, а только одну ветвь.
8. vlhown 10.01.24 07:04 Сейчас в теме
(6) Не равен. Он равен пустой ссылке.
9. lvictor58 137 11.01.24 13:01 Сейчас в теме
7. Но здесь разговор вот о чет "В статье представлен алгоритм поиска родителя нулевого уровня для элементов иерархического справочника".

8. Ну пусть равен пустой ссылке. Это и будет критерием отбора.
Оставьте свое сообщение