После столкновения с проблемой получения родителей верхнего уровня, я решил, что писать запрос каждый раз я не выдержу, поэтому решил написать функцию, которая сгенерирует текст запроса для получения родителей верхнего уровня. Далее этот текст можно передавать в конструкцию "Новый Запрос()" , или копировать и подставлять в запрос самостоятельно.
Функция принимает следующие параметры:
ИмяСправочника - имя справочника, по которому необходимо получить родителей верхнего уровня.
ИмяВременнойТаблицы - имя таблицы, куда следует поместить результат, если это необходимо.
ВключитьГруппыВРезультат - если Истина, то в таблицу попадут группы, если Ложь, то только элементы.
ИмяРеквизитаРодитель - имя реквизита, по которому строится иерархия. На случай, если добавлен отдельный реквизит (например, если справочник не иерархический).
МаксимальноеКоличествоУровнейИерархии - на сколько глубоко будет построен запрос. Укажите параметр явно, если хотите получить родителя "не выше n-го уровня".
// Текст запроса для получения родителей верхнего уровня для иерархического справочника.
//
// Параметры:
// ИмяСправочника - Строка - Имя справочника, по которому необходимо получить родителей.
// ИмяВременнойТаблицы - Строка - Имя временной таблицы для помещения в нее результата.
// Если не задана, то будет сформирована выборка данных.
// ВключитьГруппыВРезультат - Булево - Истина - в результат попадут группы / Ложь - только элементы.
// ИмяРеквизитаРодитель - Строка - Имя реквизита, по которому необходимо получить верхний уровень иерархии.
// МаксимальноеКоличествоУровнейИерархии - Число - Количество возможных уровней иерархии (не менее 2). Если не задано, то определяется автоматически:
// по настройкам справочника (если установлено ограничение), иначе 10, как значение по умолчанию.
//
// Возвращаемое значение:
// Строка - Текст запроса для получения родителей верхнего уровня.
//
&НаСервереБезКонтекста
Функция ТекстЗапросаРодителиВерхнегоУровня(ИмяСправочника, ИмяВременнойТаблицы = "", ВключитьГруппыВРезультат = Ложь,
ИмяРеквизитаРодитель = "Родитель",
МаксимальноеКоличествоУровнейИерархии = Неопределено) Экспорт
// Если количество уровней иерархии не задано, то определяем автоматически
Если МаксимальноеКоличествоУровнейИерархии = Неопределено Тогда
Попытка
МетаданныеСправочника = Метаданные.Справочники[ИмяСправочника];
Если МетаданныеСправочника.ОграничиватьКоличествоУровней Тогда
МаксимальноеКоличествоУровнейИерархииВрем = МетаданныеСправочника.КоличествоУровней;
Иначе // Значение по умолчанию
МаксимальноеКоличествоУровнейИерархииВрем = 10;
КонецЕсли;
Исключение // Справочник не найден
МаксимальноеКоличествоУровнейИерархииВрем = 10;
КонецПопытки;
Иначе // Получаем родителей не выше указанного уровня и не менее 2
МаксимальноеКоличествоУровнейИерархииВрем = Макс(МаксимальноеКоличествоУровнейИерархии, 2);
КонецЕсли;
// Выделяем часть для первого уровня, в качестве родителя указываем сам элемент
ТекстЗапроса = СтрШаблон("
|ВЫБРАТЬ
| ИсточникДанных.Ссылка КАК Ссылка,
| ИсточникДанных.Ссылка КАК Родитель
|ИЗ
| Справочник.%1 КАК ИсточникДанных", ИмяСправочника);
// Добавляем цикличную часть (начинаем с второго уровня, т.к первый уровень иерархии уже определен выше)
Для УровеньИерархии = 2 По МаксимальноеКоличествоУровнейИерархииВрем Цикл
// Проверка на последний уровень
Если УровеньИерархии = МаксимальноеКоличествоУровнейИерархииВрем Тогда
// Исключаем ситуацию, когда элемент является своим родителем
ИмяРеквизитаСсылка = ИмяРеквизитаРодитель;
ТекстВременнойТаблицы = ?(ПустаяСтрока(ИмяВременнойТаблицы), "", "
|ПОМЕСТИТЬ " + ИмяВременнойТаблицы);
Иначе
ТекстВременнойТаблицы = "";
ИмяРеквизитаСсылка = "Ссылка";
КонецЕсли;
ТекстЗапроса = СтрШаблон("
|ВЫБРАТЬ
| ИсточникДанных.Ссылка КАК Ссылка,
| ВЫБОР
| КОГДА ИсточникДанных.%2 = ЗНАЧЕНИЕ(Справочник.%1.ПустаяСсылка)
| ТОГДА ИсточникДанных.%4
| ИНАЧЕ ВложенныйЗапрос.Родитель
| КОНЕЦ КАК Родитель %5
|ИЗ
| Справочник.%1 КАК ИсточникДанных
| ЛЕВОЕ СОЕДИНЕНИЕ (%3) КАК ВложенныйЗапрос
|
|ПО ИсточникДанных.%2 = ВложенныйЗапрос.Ссылка", ИмяСправочника, ИмяРеквизитаРодитель, ТекстЗапроса, ИмяРеквизитаСсылка, ТекстВременнойТаблицы);
КонецЦикла;
// Исключаем группы из результата по параметру
Если Не ВключитьГруппыВРезультат Тогда
ТекстЗапроса = ТекстЗапроса + "
|ГДЕ НЕ ИсточникДанных.ЭтоГруппа";
КонецЕсли;
Возврат ТекстЗапроса;
КонецФункции
Также прилагаю обработку, которая позволит сгенерировать текст в режиме предприятия для его копирования и дальнейшего использования. В тексте запроса будет автоматически расставлена табуляция, если обработка открыта в той базе, где есть указанный справочник.
Проверено на следующих конфигурациях и релизах:
- 1С:ERP Управление предприятием 2, релизы 2.5.19.60