Всем привет.
Задачка вроде простая. Но с ходу лаконично не решил. Полученные решения в стиле запроса в цикле, на которые противно смотреть. И гугл не помог. Уверен, что туплю и нужно просветление.
Условие:
Имеем справочник с неограниченной иерархией элементов.
В поле ввода на форме (УФ) выбираем элемент лежащий на любом уровне. Жмем кнопку, по которой программа уходит на сервер.
Там надо получить переменную содержащую дерево значений, в корне которого одна строка, содержащая выбранный элемент. В подчиненных строка подчиненные элементы в соответствии со структурой справочника.

Требования:
1. В дереве не должно быть дублей. Запрос с итогами при выгрузке в дерево делает элемент в итогах самого себя.
2. Запрос внутри цикла или внутри рекурсии - нет.
3. Удалять строки из результата выполнения запроса, бегая циклом по дереву - нет.
4. Красиво, лаконично и ПРАВИЛЬНО.

Пример:
имеем справочник:
1
1.1
1.1.1
1.1.2
1.1.2.1
1.1.2.2
1.1.3
1.2
1.3
1.3.1
1.3.1.1

Выбрали элемент "1.1" и получим дерево:
1.1
1.1.1
1.1.2
1.1.2.1
1.1.2.2
1.1.3
---
monkbest, ну если вам так было проще, никто же за вас код писать не будет.
Я просто предложил, то как я бы решал такую задачу.
---
monkbest, чем не страивает такое решение:
```1c
    ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка
    ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ГДЕ
    Номенклатура.Ссылка В ИЕРАРХИИ(&Ссылка)
    ИТОГИ ПО
    Ссылка ИЕРАРХИЯ
```
---
Только потом результат нужно обработать по итоговым записям, чтобы визуально не было дублей, хоть таковыми они и не являются в запросе.
---
Хотя вот так более красиво вышло
```1c
    ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка
    ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ГДЕ
    Номенклатура.Родитель В ИЕРАРХИИ(&Ссылка)
    ИТОГИ ПО
    Ссылка ТОЛЬКО ИЕРАРХИЯ
    АВТОУПОРЯДОЧИВАНИЕ
```
---
Xershi, не будет работать, ибо все верхние уровни иерархии тоже попадут в выборку, а аффтору это не надо.

Сделать "лаконично" - это вне 1С. Рекурсия тут как раз самое то. Есть еще вариант выгрузить в дерево и найти в нем, после чего вернуть строку с найденным, которую принимать за корневую. Но для правильной иерархии придется компоновать в дерево значений, ибо в запросе будет задваиваться родитель на подчиненных уровнях, если его не убивать (типа ГДЕ не Сцылка в (список_родителей) ).
---
starik-2005, ну так я же и написал, потом его нужно обработать.
Единственное, что верхний уровень так и остается, это же дерево справочника. Поэтому если нужно уже дерево без связи с деревом справочника, то нужно будет его потом дополнительно собрать.

Кстати как-то видел на ИС, что собирали дерево с нуля для похожих задач.

Так что если верхний уровень критичен без собственной сборки дерева не обойтись, но запрос в (4) как раз и позволит его собрать.
---
Xershi, в номенклатуре иерархия папок и для решения моей задачи остается отсечь у дерева только голову, т.е. одну из ветвей сделать корнем (что я пока не очень представляю как сделать без полного обхода исходного дерева и строительства нового).
В случае иерархии элементов (например подразделения) еще и двоятся элементы, т.к. каждый сам по себе элемент и заодно итог для подчиненных

Вот такой запрос:

```1c
    ВЫБРАТЬ
    ИС_ЭтапыРабот.Ссылка КАК Ссылка,
    ИС_ЭтапыРабот.Код,
    ИС_ЭтапыРабот.Родитель
    ИЗ
    Справочник.ИС_ЭтапыРабот КАК ИС_ЭтапыРабот
    ГДЕ
    ИС_ЭтапыРабот.Ссылка В ИЕРАРХИИ(&Родитель)
    ИТОГИ ПО
    Ссылка ТОЛЬКО ИЕРАРХИЯ
```

вывел вот такую некрасивость (рис 1)
обратите внимание на элемент с кодом 135, он отобразился 2 раза, и обе строки технически идентичны
а вот как выглядит справочник на самом деле (рис 2)
---
monkbest, я же вам уже писал. Получив результат его нужно обработать!
То что записи визуально идентичны, в результате запроса сильно отличаются!
Так что перечитайте (7)!
---
СКД и ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений.
---
antz, не слишком ли круто, создавать кучу лишних сущностей (макет, компановщик, процессор и т.д.) чтобы решить такую простую задачу?
---
Видел что-то похожее тут: http://1c-pro.ru/threads/v-ierarxii-naoborot.18291/
---
Продумывая способ обработки дерева, которое выгружает запрос, я прихожу к выводу, а может и не надо в запросе итогов делать, а получить все элементы и собрать дерево рекурсивно получая родителя. Создаваемые ветки кэшировать в соответствие, чтобы не искать их циклом. Ведь найти строки работает только в конкретной ветке дерева, а не во всем дереве.

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

Короче, я все еще в поисках максимально красивого решения
---
Точно, признак остановки рекурсии - родитель = выбранному элементу.
---
monkbest, в любом случае проход начнется с вверху и пока он не дойдет до нужного значения новое дерево собирать не нужно, ну а далее отсекаем детальные записи равные верхним итогам. Работы на час.
---
Xershi, у меня получилось снизу, для этого строку добавлять надо "на выходе" из рекурсии, чтобы родительская ветка уже была.
---
monkbest, ну если вам так было проще, никто же за вас код писать не будет.
Я просто предложил, то как я бы решал такую задачу.
---
вот, что вылезло из моей мысли о том, что запрос нужен без итогов
родителей получаю не через точку, а получил из в запросе, так я ушел от обращения к БД в цикле

можно изящнее?

критикуйте:

```1c
    &НаСервере
    //точка входа основная процедура формирующая дерево
    Процедура СформироватьНаСервере()
    //1. Создадим дерево с одной строкой в корне
    Дерево = Новый ДеревоЗначений;
    Дерево.Колонки.Добавить("Этап");
    Корень = Дерево.Строки.Добавить();
    //этап - переменная формы, которую выбрали в поле ввода
    Корень.Этап= Этап;
    //2. Найдем все подчиненные этапы работ
    Запрос = Новый Запрос("ВЫБРАТЬ
    | ЭтапыРабот.Ссылка,
    | ЭтапыРабот.Родитель
    |ИЗ
    | Справочник.ЭтапыРабот КАК ЭтапыРабот
    |ГДЕ
    | ЭтапыРабот.Ссылка В ИЕРАРХИИ(&корень)");
    Запрос.УстановитьПараметр("корень", Этап);
    рез = Запрос.Выполнить();
    тз = рез.Выгрузить();
    КэшУжеПрописаных = Новый Соответствие;
    КэшУжеПрописаных.Вставить(Этап, Корень);
    Для Каждого стр Из тз Цикл

    СунутьВНужнуюВеткуДерева(Корень, КэшУжеПрописаных, тз, стр);
    КонецЦикла;
    //КОНЕЦ, в переменной дерево лежит нужное нам дерево
    КонецПроцедуры

    &НаСервере
    Процедура СунутьВНужнуюВеткуДерева(Корень, КэшУжеПрописаных, тз, обрабатываемаяСтрока)
    //ищем в кэше саму ссылку
    КэшСсылки = КэшУжеПрописаных.Получить(обрабатываемаяСтрока.Ссылка);
    Если КэшСсылки<>Неопределено тогда
    Возврат;
    КонецЕсли;

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

    //ищем в кэше родителя, его там не может не быть!!!, но мы проверим
    КэшРодителя = КэшУжеПрописаных.Получить(обрабатываемаяСтрока.Родитель);
    Если КэшРодителя<>Неопределено тогда
    //добавляем в найденную ветку в кэше ссылку
    ДобавляемаяСтрока = КэшРодителя.Строки.Добавить();
    ДобавляемаяСтрока.Этап= обрабатываемаяСтрока.Ссылка;
    //кэшируем новую строку
    КэшУжеПрописаных.Вставить(обрабатываемаяСтрока.Ссылка, ДобавляемаяСтрока);
    КонецЕсли;
    КонецПроцедуры
```
---
Спасибо!
---
It works! Thanks a lot
---
Не работает только когда ссылки друг на друга указывают