Всем привет.
Заморочился тут с задачей уровня "вылизывания яиц".(увлечения скорости и уменьшения нагрузки на SQL)
Есть справочник, типовой, иерархия групп (возьмем номенклатуру), с переменной вложенностью (ХЗ сколько может быть родителей).(см картинку Справочник).
Так вот вывести в виде дерева, это без проблем (см дерево)
А вот вывести в плоскую не удается.(см плоская)
Вариант через "ИЛИ ....Спр.Родитель.Родитель...." не предлагать(так сделано).
Настройка СКД прикреплена с группировкой.
Пробовал различные варианты, через склейку двух источников,
1) в тексте запроса набора данных получаем два поля "Ссылка" (для второго поля установим синоним "СсылкаДоп")
2) добавляем в ресурсы поле "СсылкаДоп", где в выражении просто указываем "СсылкаДоп" без каких либо агрегатных функций
3) в настройках отчета добавляем группировки по полю "Ссылка" - без иерархии. В настройках ЭТОЙ группировки для параметра "Расположение группировки" устанавливаем значение "Нет"
4) добавляем подчиненную группировку по полю "Ссылка" - Иерархия. В ЭТУ группировку:
4.1 выводим ресурс "СсылкаДоп"
4.2 добавляем группу отборов с видом И (можно и "ИЛИ" - без разницы) и устанавливаем для нее применение "После группировки или для иерархии".
4.3 в группу отборов добавляем отбор: "Системные поля. Уровень" Равен 2
В рамках задачи "увлечения скорости и уменьшения нагрузки на SQL", предлагаю поиск верхнего родителя перенести с sql на плечи внутреннего языка. Получается довольно шустро даже если выбирать все элементы справочника. Суть кода в этой процедуре:
Функция ПолучитьРодителейВерхнегоУровня(МассивСсылок)
Запрос = Новый Запрос(
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Родитель КАК Родитель
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В(&МассивСсылок)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Родитель
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоГруппа");
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
Соответствие = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Соответствие.Вставить(Выборка.Ссылка, Выборка.Родитель);
КонецЦикла;
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Результат.Колонки.Добавить("РодительВерхнегоУровня", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ПустаяСсылка = Справочники.Номенклатура.ПустаяСсылка();
Для Каждого Ссылка Из МассивСсылок Цикл
НоваяСтрока = Результат.Добавить();
НоваяСтрока.Ссылка = Ссылка;
РодительВерхнегоУровня = ПустаяСсылка;
Родитель = Соответствие[Ссылка];
Пока Родитель <> ПустаяСсылка Цикл РодительВерхнегоУровня = Родитель; Родитель = Соответствие[Родитель] КонецЦикла;
НоваяСтрока.РодительВерхнегоУровня = РодительВерхнегоУровня;
КонецЦикла;
Возврат Результат
КонецФункции
Показать
Используется дополнительная схема для получения массива используемой номенклатуры.
то есть механика будет вставляться в отчеты.
и наверное в цикле должно быть
Родитель = Родитель.Родитель;
А если учесть что каждое обращение через точку это запрос и если учесть что это разные запросы(практически запрос в цикле), то данная конструкция ляжет на 100 000 номенклатуры с четырьмя уровнями (в максималке) группировок.
:(
(8)На самом деле в (7) здравая идея.
Вариация с функцией общего модуля.
1) в СКД добавляем параметр, например, АдресСоответствияРодителей.
2) в СКД добавляем вычисляемое поле РодительВерхнегоУровня.
3) в качестве формулы для поля РодительВерхнегоУровня делаем вызов функции общего модуля, в которой будет 2 параметра.
1 - родитель номенклатуры
2 - параметр АдресСоответствияРодителей
4) в функции ОМ прописываем - если параметр АдресСоответствияРодителей пустой - формируем соответствие из пар родитель номенклатуры и родитель верхнего уровня для всех групп справочника Номенклатура.
И помещаем во временное хранилище. Адрес временного хранилища присваиваем в параметр АдресСоответствияРодителей.
5) далее в этой же функции получаем из соответствия для переданного родителя - родителя верхнего уровня.
6) для лучшей работы можно сделать из ОМ вызов ОМ с флагом повторное использование на время вызова и уже в этом модуле реализовать функцию заполнения и поиска родителя.
(13)Можно запросом.
Заложиться, на конкретное количество уровней иерархии, например 10, и сформировать запрос транзитивного замыкания для данного количества уровней иерархии, как в публикации https://infostart.ru/public/160707/ (3. Определение прародителя (родителя верхнего уровня) в пакетном запросе) и с ним уже соединиться.
Хотя например, если это отчет (например, внешний), то можно перед выполнением отчета определить максимальную глубину иерархии справочника и сформировать транзитивный запрос в источнике данных СКД под конкретную глубину.
(18) По материалам публикации сделать запрос транзитивного замыкания на 10 (условно, можно больше) уровней иерархии. Этот запрос поместить в набор данных Запрос в СКД.
Соединиться с этим набором данных.
Все.
А может лучше будет хранить верхних родителей, а не каждый раз их вычислять?
Например, создаем регистр сведений с измерением "Группа номенклатуры" и ресурсом "Группа верхнего уровня". Создает подписку на запись группы номенклатуры для заполнения регистра. В запросе реализуем соединение "Номенклатура.Родитель = НовыйРегистр.ГруппаНоменклатуры".
Тогда, как вариант - создать внешний набор данных по материалам публикации https://infostart.ru/public/160707/ Соединить набор Номенклатура с внешним набором данных
Все эти решения основаны на пакетных запросах и цикличном обращение.
Как писал выше задача состоит в том что бы сделать это все одной схемой СКД без применения внешних процедур и прочего.
(21) я может плохо вижу? в вашем примере рассматривается решение через прокручивание циклом постройки текста запроса.
Данные способ применен еще в ЗУП 2.5 и часто используется.
В условиях задачи стоит что нужно на Компоновки данных сопоставить так источники, что бы получить подобный результат.
По материалам публикации сделать запрос транзитивного замыкания на 10 (условно, можно больше) уровней иерархии. Этот запрос поместить в набор данных Запрос в СКД.
Заранее, сейчас получить текст запроса и итоговый текст вставить в запрос СКД.
Без использования внешних функций и циклов на этапе выполнения СКД.
Для получения текста запроса для нужного уровня вложенности - воспользоваться процедурами из публикации по ссылке выше.
(25)Да, абсолютно правильно. Без внешних данных, все в одной компоновке.
Была идея получить все группы верхнего уровня.
Получить все элементы подчиненные с отбором по иерархии
Склеить это все с применением параметра.
1) в тексте запроса набора данных получаем два поля "Ссылка" (для второго поля установим синоним "СсылкаДоп")
2) добавляем в ресурсы поле "СсылкаДоп", где в выражении просто указываем "СсылкаДоп" без каких либо агрегатных функций
3) в настройках отчета добавляем группировки по полю "Ссылка" - без иерархии. В настройках ЭТОЙ группировки для параметра "Расположение группировки" устанавливаем значение "Нет"
4) добавляем подчиненную группировку по полю "Ссылка" - Иерархия. В ЭТУ группировку:
4.1 выводим ресурс "СсылкаДоп"
4.2 добавляем группу отборов с видом И (можно и "ИЛИ" - без разницы) и устанавливаем для нее применение "После группировки или для иерархии".
4.3 в группу отборов добавляем отбор: "Системные поля. Уровень" Равен 2
(35) логика следующая:
СКД при выводе иерархии заменяет все значения в поле группировки на значение родителя - поэтому, если нам нужно вывести сам элемент и его родителя на одном уровне нам понадобится дополнительное поле, в котором значение не будет заменено.
так как в группировку с иерархией нельзя добавлять другие поля, то нам понадобится ресурс - помещаем в значение ресурса сам элемент, т.е. поле значение которого не будет замещаться СКД.
так как ресурс мы хотим выводить на уровне самого верхнего родителя, а такому уровню может соответсвовать несколько значений детальных записей, то нам нужно обеспечить, чтобы родителей выводилось столько же сколько и детальных записей. Для этого добавим группировку по полю "Ссылка" бех иерархии, а так как по условиям задачи вывод такой информации не нужен, то убираем у этой группировки вывод. Этим мы обеспечили, что для всех нижестоящих группировок расчет ресурсов будет происходить в разрезе конкретной ссылки, а не родителя
* для узучения можно вернуть этой группировки видимость, тогда будет более понятно что происходит
дальше все стандартно для такой ситуации - добавляем группировку по иерархии и отбором ограничиваем вывод этой иерархии.
*отбором можно отсекать записи находящиеся строго ниже по иерархии - не получится отсекать промежуточные записи иерархии или находящиеся выше
(34)
Посмотрел Вашу схему.
Она выводит самый старший уровень группировки.
А как вывести в плоскость всю иерархию не понятно.
Отборы не позволяют выводить младший уровень без старшего.