Как получить родительское подразделение из иерархического справочника в 1С:Предприятие 8.3

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием IT и автоматизация бизнеса
← На главную

При работе с иерархическими справочниками в 1С (особенно в сложных конфигурациях вроде ERP 2 или ЗУП 3) программисты часто сталкиваются с задачей: как по выбранному элементу (например, удаленному отделению) быстро и корректно найти его «головное» подразделение. Сложность заключается в том, что уровень вложенности может быть разным: где-то это второй уровень, а где-то — пятый. В этой статье мы разберем несколько эффективных способов решения этой задачи, начиная от простых программных методов и заканчивая оптимизированными запросами к системным регистрам.

Метод 1: Использование специализированных регистров сведений (оптимально для ERP и ЗУП)

В современных конфигурациях на базе 1С:ERP и 1С:Зарплата и управление персоналом 3.1 разработчики платформы уже позаботились об оптимизации работы с иерархией. Вместо того чтобы каждый раз «взбираться» по дереву родителей, мы можем использовать данные из специальных регистров сведений, которые хранят полную структуру подчиненности. Разберем, как это работает.

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

Проанализируем пример запроса, который позволяет найти подразделение определенного уровня:


ВЫБРАТЬ
    Иерархия.ВышестоящееПодразделение КАК ГоловноеПодразделение
ИЗ
    РегистрСведений.ПодчиненностьПодразделенийОрганизаций КАК Иерархия
ГДЕ
    Иерархия.Подразделение = &ВыбранноеОтделение
    И Иерархия.ВышестоящееПодразделение.Родитель = ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)

Этот подход крайне эффективен, так как регистр уже содержит все связи между всеми уровнями. Нам не нужно делать рекурсию — мы просто выбираем ту запись, где ВышестоящееПодразделение является элементом верхнего уровня (его родитель пуст).

Метод 2: Рекурсивный поиск на встроенном языке

Если ваша конфигурация не содержит вспомогательных регистров или структура справочника является нестандартной, можно воспользоваться классической рекурсией. Рассмотрим ситуацию, когда нам нужно подниматься вверх по дереву до тех пор, пока мы не встретим элемент, удовлетворяющий нашим условиям (например, отсутствие родителя или наличие определенного признака).

Разберем по шагам создание такой функции:


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

Важный момент: При написании рекурсии для справочников с иерархией элементов (а не групп) всегда следует помнить о риске зацикливания. Рекомендуется добавлять счетчик итераций, чтобы поиск не стал бесконечным, если в данных допущена ошибка.

Метод 3: Использование функций Библиотеки стандартных подсистем (БСП)

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

Функция ОбщегоНазначения.ПолучитьВсехРодителей(Ссылка) возвращает массив всех вышестоящих элементов. Это очень удобно: мы получаем список от непосредственного родителя до самого «корня». Рассмотрим, как извлечь из этого массива нужное нам подразделение:

  1. Вызываем функцию БСП для получения массива родителей.
  2. Если массив не пуст, анализируем его элементы. Обычно «головное подразделение» находится в самом конце массива (самый верхний уровень).
  3. Выбираем нужный индекс и получаем готовую ссылку.

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

Метод 4: Пакетный запрос с левыми соединениями

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

Выясним причину, почему это иногда лучше рекурсии: запрос выполняется на стороне сервера СУБД и может быть быстрее при обработке больших массивов данных. Мы соединяем таблицу справочника саму с собой через поле Родитель несколько раз (столько, сколько максимально уровней может быть в справочнике).


ВЫБРАТЬ
    Спр1.Ссылка КАК Элемент,
    ЕСТЬNULL(Спр4.Ссылка, ЕСТЬNULL(Спр3.Ссылка, ЕСТЬNULL(Спр2.Ссылка, Спр1.Ссылка))) КАК ГоловнойРодитель
ИЗ
    Справочник.Подразделения КАК Спр1
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Подразделения КАК Спр2 ПО Спр1.Родитель = Спр2.Ссылка
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Подразделения КАК Спр3 ПО Спр2.Родитель = Спр3.Ссылка
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Подразделения КАК Спр4 ПО Спр3.Родитель = Спр4.Ссылка
ГДЕ
    Спр1.Ссылка = &ВыбранныйЭлемент

Ограничение: Согласно рекомендациям ИТС, не стоит использовать более 7-10 соединений в одном запросе, так как это может существенно снизить производительность. Однако для большинства задач с глубиной иерархии в 3-5 уровней этот метод работает безотказно.

Подведем итоги

Мы рассмотрели несколько подходов к поиску подразделений в иерархии 1С. Выбор метода зависит от контекста:

Помните, что работа с иерархией элементов требует внимательности к деталям: всегда проверяйте, не является ли выбранный элемент сам по себе «головным», и корректно обрабатывайте пустые ссылки.

← На главную