1С 8.3 Получение родителей элемента - Программист 1С Минск. Автоматизация бизнеса.

Перейти к контенту

1С 8.3 Получение родителей элемента

Данные > Примеры кода 1С > 1С 8.3 Справочники
Перейти в раздел примеры кода 1С 8.3:
Обновлено 04.08.2025:

Функция ТекстЗапросаДляПолученияРодителейВсехУровнейИерархии генерирует запрос для получения всех родителей в иерархической структуре справочника в 1С. Полезна для сложных аналитических запросов, где нужно учитывать всю иерархию элементов, а не только непосредственных родителей. Пруф кода автора.

Создает запрос, который:
  • Находит все родительские элементы для каждого элемента справочника
  • Учитывает все уровни иерархии
  • Может работать как с обычными элементами, так и с группами
  • Поддерживает различные варианты вывода результатов

Логика работы:
  • Сначала создается "пролог" запроса, который формирует начальные связи (дуги длиной 1) между элементами и их непосредственными родителями.
  • Затем многократно применяется "рефрен", который находит связи большей длины путем соединения уже найденных связей.
  • В конце формируется "эпилог", который выводит итоговый результат в нужном формате.
  • Все шаблонные строки заменяются на реальные значения параметров.

Особенности:
  • Использует алгоритм нахождения транзитивного замыкания для иерархии
  • Поддерживает параметризацию имен таблиц и колонок
  • Позволяет ограничивать набор элементов, для которых ищутся родители
  • Может выводить результат как во временную таблицу

Пример использования:
Запрос = ТекстЗапросаДляПолученияРодителейВсехУровнейИерархии("Номенклатура",10,"Родитель",Истина,"ВТРодителиНоменклатуры");
Функция генерирует запрос для получения всех родителей в иерархии справочника с учетом всех уровней вложенности в 1С 8.3:
// Транзитивное замыкание иерархии
//
// Параметры:
//  ИмяСправочника          -  строка - Имя справочника (обязательный)
//  МаксимальнаяДлинаПути   - число  - Макс. уровней вложенности (по умолчанию 8)
//  ИмяРеквизитаИерархии    - строка - Реквизит иерархии (по умолчанию "Родитель")
//  ПолучитьРодителейГрупп  - булево - Включать группы (по умолчанию Ложь)
//  ИмяВременнойТаблицы     - строка - Имя ВТ для результата (необязательный)
//  ИмяПараметраСЭлементами - строка - Ограничение по элементам (необязательный)
//  ИмяКолонкиЭлемент       - строка - Имя колонки элемента (по умолчанию "Ссылка")
//  ИмяКолонкиРодитель      - строка - Имя колонки родителя (по умолчанию "Родитель")
//
// Возвращаемое значение:
//  Строка - текст запроса для получения иерархии
//
&НаКлиентеНаСервереБезКонтекста
Функция ТекстЗапросаДляПолученияРодителейВсехУровнейИерархии(
   Знач ИмяСправочника,
   Знач МаксимальнаяДлинаПути = 8,
   Знач ИмяРеквизитаИерархии = "Родитель",
   Знач ПолучитьРодителейГрупп = Ложь,
   Знач ИмяВременнойТаблицы = "",
   Знач ИмяПараметраСЭлементами = "",
   Знач ИмяКолонкиЭлемент = "Ссылка",
   Знач ИмяКолонкиРодитель = "Родитель")

   // ========== ПОДГОТОВКА ЧАСТЕЙ ЗАПРОСА ==========
   // 1. Пролог запроса - создаем начальные связи (дуги длиной 1)
   Пролог =
   "ВЫБРАТЬ
        |    #ИмяРеквизитаИерархии КАК НачалоДуги,
        |    Ссылка КАК КонецДуги
        |ПОМЕСТИТЬ ЗамыканияДлины1
        |ИЗ Справочник.#ИмяСправочника
        |ГДЕ #ИмяРеквизитаИерархии <> Значение(Справочник.#ИмяСправочника.ПустаяСсылка)
        |ОБЪЕДИНИТЬ
        |ВЫБРАТЬ
        |    Ссылка,
        |    Ссылка
        |ИЗ Справочник.#ИмяСправочника
        |#СтрУсловия;";

   // Формируем условия выборки
   СтрУсловия = "";

   // Если задан параметр с элементами - добавляем условие IN
   Если Не ПустаяСтрока(ИмяПараметраСЭлементами) Тогда
       СтрУсловия = "ГДЕ Ссылка В(&" + ИмяПараметраСЭлементами + ")";
   КонецЕсли;

   // Если не нужно включать группы - добавляем соответствующее условие
   Если Не ПолучитьРодителейГрупп Тогда
       Если Не ПустаяСтрока(СтрУсловия) Тогда
           СтрУсловия = СтрУсловия + " И ЭтоГруппа = Ложь";
       Иначе
           СтрУсловия = "ГДЕ ЭтоГруппа = Ложь";
       КонецЕсли;
   КонецЕсли;

   // Вставляем условия в пролог
   Пролог = СтрЗаменить(Пролог, "#СтрУсловия", СтрУсловия);

   // 2. Рефрен запроса - рекурсивно находим связи большей длины
   Рефрен =
   "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    ПерваяДуга.НачалоДуги,
        |    ВтораяДуга.КонецДуги
        |ПОМЕСТИТЬ ЗамыканияДлины#2
        |ИЗ ЗамыканияДлины#1 КАК ПерваяДуга
        |ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины#1 КАК ВтораяДуга
        |    ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
        |УНИЧТОЖИТЬ ЗамыканияДлины#1;";

   // 3. Эпилог запроса - формируем итоговый результат
   Эпилог =
   "ВЫБРАТЬ
        |    НачалоДуги КАК #ИмяКолонкиРодитель,
        |    КонецДуги КАК #ИмяКолонкиЭлемент" +
       ?(ПустаяСтрока(ИмяВременнойТаблицы), "", " ПОМЕСТИТЬ " + ИмяВременнойТаблицы) +
      " ИЗ ЗамыканияДлины#2
        |ГДЕ НачалоДуги <> КонецДуги"

   // ========== ФОРМИРОВАНИЕ ТЕКСТА ЗАПРОСА ==========
   ТекстЗапроса = Пролог;
   ТекущаяДлинаЗамыканий = 1;

   // Рекурсивно находим все связи, удваивая длину на каждом шаге
   Пока ТекущаяДлинаЗамыканий < МаксимальнаяДлинаПути Цикл
       НоваяДлина = 2 * ТекущаяДлинаЗамыканий;

       // Добавляем очередную часть запроса
       ТекстЗапроса = ТекстЗапроса + СтрЗаменить(СтрЗаменить(Рефрен,
      "#1", Формат(ТекущаяДлинаЗамыканий, "ЧГ=0")),
      "#2", Формат(НоваяДлина, "ЧГ=0"));

       ТекущаяДлинаЗамыканий = НоваяДлина;
   КонецЦикла;

   // Добавляем эпилог и очистку временных таблиц
   ТекстЗапроса = ТекстЗапроса +
   СтрЗаменить(Эпилог, "#2", Формат(ТекущаяДлинаЗамыканий, "ЧГ=0")) +
  "; УНИЧТОЖИТЬ ЗамыканияДлины" + Формат(ТекущаяДлинаЗамыканий, "ЧГ=0");

   // ========== ЗАМЕНА ПЛЕЙСХОЛДЕРОВ НА РЕАЛЬНЫЕ ЗНАЧЕНИЯ ==========
   ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяСправочника",       ИмяСправочника);
   ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяРеквизитаИерархии", ИмяРеквизитаИерархии);
   ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяКолонкиЭлемент",    ИмяКолонкиЭлемент);
   ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяКолонкиРодитель",   ИмяКолонкиРодитель);

   Возврат ТекстЗапроса;

КонецФункции
Обновлено 2023-2024:
Получение родителей элемента Справочника или Плана видов характеристик в 1С 8.3:
&НаСервере
Функция ПолучениеВсехРодителейЭлемента(ЭлементСсылка, Знач КолВыбЗаОперацию = 10)

   
// ЭлементСсылка - СправочникСсылка, ПланВидовХарактеристикСсылка - Ссылка на элемент, родителей которого нужно найти
    // КолВыбЗаОперацию - Количество выбираемых родителей за одно выполнение функции запроса
   
РодителиЭлемента = Новый Массив;
    Если НЕ
ЗначениеЗаполнено(ЭлементСсылка) Тогда
        Возврат
РодителиЭлемента;
    КонецЕсли;

   
МетаданныеЭл = ЭлементСсылка.Метаданные();
    Если
МетаданныеЭл.ОграничиватьКоличествоУровней Тогда
       
// Минимальное количество или из переданного или из ограничения количества уровней метаданных
       
КолВыбЗаОперацию = Мин(КолВыбЗаОперацию, МетаданныеЭл.КоличествоУровней);
    КонецЕсли;

   
МассивПолей = Новый Массив;
   
ВыбПоле = "Родитель";
    Для
НомерРодителя = 1 По КолВыбЗаОперацию Цикл
       
МассивПолей.Добавить(ВыбПоле);
       
ВыбПоле = ВыбПоле + ".Родитель";
    КонецЦикла;

   
ТекстЗапроса = "ВЫБРАТЬ %1 ИЗ %2 ГДЕ Ссылка = &ТекЭлемент";
   
ТекстЗапроса = СтрШаблон(ТекстЗапроса, СтрСоединить(МассивПолей, ","), МетаданныеЭл.ПолноеИмя());

   
Запрос = Новый Запрос(ТекстЗапроса);
   
ТекЭлемент = ЭлементСсылка;
    Пока
ЗначениеЗаполнено(ТекЭлемент) Цикл

       
Запрос.УстановитьПараметр("ТекЭлемент", ТекЭлемент);
       
Результат = Запрос.Выполнить();
        Если
Результат.Пустой() Тогда
            Прервать;
        КонецЕсли;

       
Выборка = Результат.Выбрать();
       
Выборка.Следующий();
        Для
НомерКолонки = 0 По Результат.Колонки.Количество() - 1 Цикл
           
ТекЭлемент = Выборка[НомерКолонки];
            Если
ЗначениеЗаполнено(ТекЭлемент) Тогда
               
РодителиЭлемента.Добавить(ТекЭлемент);
            Иначе
                Прервать;
            КонецЕсли;
        КонецЦикла;

    КонецЦикла;

   
// Возвращаем Массив[СправочникСсылка, ПланВидовХарактеристикСсылка] со всеми родителями элемента
   
Возврат РодителиЭлемента;

КонецФункции
Получение запросом родителей элемента справочника в 1С 8.3:
&НаСервере
Процедура ПолучениеЗапросомРодителейЭлементаСправочника(СсылкаНаКонтрагента)

   
КонтрагентСсылка=СсылкаНаКонтрагента;
   
// Специальных средств для получения родителей элементов справочника в запросе нет,
    // поэтому целесообразно родителей перебирать в цикле
    // На примере справочника контрагентов с макс.глубиной 10 вложений
   
Запрос = Новый Запрос("ВЫБРАТЬ
    |   Контрагент.Родитель,
    |   Контрагент.Родитель.Родитель,
    |   Контрагент.Родитель.Родитель.Родитель,
    |   Контрагент.Родитель.Родитель.Родитель.Родитель,
    |   Контрагент.Родитель.Родитель.Родитель.Родитель.Родитель,
    |   Контрагент.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель,
    |   Контрагент.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель,
    |   Контрагент.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель,
    |   Контрагент.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель,
    |   Контрагент.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель,
    |ИЗ
    |   Справочник.Контрагенты КАК Контрагент
    |ГДЕ
    |   Контрагент.Ссылка = &КонтрагентСсылка"
);

    Пока Истина Цикл

       
Запрос.УстановитьПараметр("КонтрагентСсылка", КонтрагентСсылка);
       
Результат = Запрос.Выполнить();
        Если
Результат.Пустой() Тогда
            Прервать;
        КонецЕсли;

       
Выборка = Результат.Выбрать();
       
Выборка.Следующий();
        Для
НомерКолонки = 0 По Результат.Колонки.Количество() - 1 Цикл
           
КонтрагентСсылка = Выборка[НомерКолонки];
            Если
КонтрагентСсылка = Справочники.Контрагенты.ПустаяСсылка() Тогда
                Прервать;
            Иначе
               
Сообщить("Родитель элемента "+КонтрагентСсылка);
            КонецЕсли;
        КонецЦикла;

        Если
КонтрагентСсылка = Справочники.Контрагенты.ПустаяСсылка() Тогда
            Прервать;
        КонецЕсли;

    КонецЦикла;

КонецПроцедуры
Получить всех родителей элемента (Экспортная) в 1С 8.3:
// Возвращает всех родителей элемента, согласно рекомендациям на ИТС:
// см. https://its.1c.ru/db/metod8dev/content/2659/hdoc
// Источник: https://github.com/SeiOkami/CollectionMethodsOneS/issues/14
//
// Параметры:
//  Ссылка  - СправочникСсылка, ПланВидовХарактеристикСсылка - Ссылка на элемент, родителей которого нужно найти
//  КоличествоВыбираемыхЗаПорцию  - Число - Количество выбираемых родителей за одно выполнение запроса.
//        Используется минимальное число из переданного и ограничения количества уровней в конфигураторе
//
// Возвращаемое значение:
//   Массив из СправочникСсылка, ПланВидовХарактеристикСсылка - массив с родителями элемента
//
// Пример:
//
//   Результат = РодителиЭлемента(ЭлементБазы);
//   //Результат - массив с ссылками на родителей элемента
//
Функция РодителиЭлемента(Знач Ссылка, Знач КоличествоВыбираемыхЗаПорцию = 5) Экспорт

   РодителиЭлемента = Новый Массив; // Массив из см. РодителиЭлемента.Ссылка
   Если НЕ ЗначениеЗаполнено(Ссылка) Тогда
       Возврат РодителиЭлемента;
   КонецЕсли;

   МетаданныеЭлемента = Ссылка.Метаданные();
   Если МетаданныеЭлемента.ОграничиватьКоличествоУровней Тогда
       КоличествоВыбираемыхЗаПорцию = Мин(КоличествоВыбираемыхЗаПорцию, МетаданныеЭлемента.КоличествоУровней);
   КонецЕсли;

   ВыбираемыеПоля = Новый Массив; // Массив из Строка
   ВыбираемоеПоле = "Родитель";
   Для НомерРодителя = 1 По КоличествоВыбираемыхЗаПорцию Цикл
       ВыбираемыеПоля.Добавить(ВыбираемоеПоле);
       ВыбираемоеПоле = ВыбираемоеПоле + ".Родитель";
   КонецЦикла;

   ТекстЗапроса = "ВЫБРАТЬ %1 ИЗ %2 ГДЕ Ссылка = &ТекущийЭлемент";
   ТекстЗапроса = СтрШаблон(ТекстЗапроса, СтрСоединить(ВыбираемыеПоля, ","), МетаданныеЭлемента.ПолноеИмя());
   Запрос = Новый Запрос(ТекстЗапроса);

   ТекущийЭлемент = Ссылка;
   Пока ЗначениеЗаполнено(ТекущийЭлемент) Цикл

       Запрос.УстановитьПараметр("ТекущийЭлемент", ТекущийЭлемент);
       Результат = Запрос.Выполнить(); //@skip-check query-in-loop
       Если Результат.Пустой() Тогда
           Прервать;
       КонецЕсли;

       Выборка = Результат.Выбрать();
       Выборка.Следующий();
       Для НомерКолонки = 0 По Результат.Колонки.Количество() - 1 Цикл
           ТекущийЭлемент = Выборка[НомерКолонки]; // см. РодителиЭлемента.Ссылка
           Если ЗначениеЗаполнено(ТекущийЭлемент) Тогда
               РодителиЭлемента.Добавить(ТекущийЭлемент);
           Иначе
               Прервать;
           КонецЕсли;
       КонецЦикла;

   КонецЦикла;

   Возврат РодителиЭлемента;

КонецФункции
// MIT License
// Copyright (c) 2024 SeiOkami
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Обновлено 2021:
Получить родителей элемента прямой работой с объектом в 1С 8.3:
// Процедура выводит в сообщения всех родителей элемента в иерархии
//
// Параметры:
//  Элемент - СправочникОбъект, ДокументОбъект или другой объект с иерархией - элемент, для которого нужно вывести родителей
//
Процедура ВывестиРодительскуюИерархию(Элемент) Экспорт

   // Проверяем, что переданный объект существует
   Если Элемент = Неопределено Тогда
       ВызватьИсключение "Не передан элемент для вывода иерархии!";
   КонецЕсли;

   // Получаем родителя текущего элемента
   Родитель = Элемент.Родитель;

   // Если родитель существует (иерархия не закончилась)
   Если Родитель <> Неопределено И НЕ Родитель.Пустая() Тогда

       // Выводим текущий элемент
       Сообщить(Элемент);

       // Рекурсивно вызываем эту же функцию для родителя
       ВывестиРодительскуюИерархию(Родитель);
   Иначе
       // Выводим последний элемент в цепочке (корневой)
       Сообщить(Элемент);
   КонецЕсли;

КонецПроцедуры
0
комментарии
____________________
Copyright©, «Программист 1С в г.Минске», 11.03.2021
Перепечатка текста и фотографий разрешена при наличии прямой ссылки на источник
Яндекс.Метрика
Назад к содержимому