Как получить родителя первого уровня элемента справочника в консоли запросов 1С

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

При работе с иерархическими справочниками в 1С, такими как ДоговорыКонтрагентов, Номенклатура или Подразделения, часто возникает необходимость найти «корень» иерархии — то есть родителя самого верхнего уровня для конкретного элемента. Сложность заключается в том, что уровень вложенности может быть разным, а стандартный язык запросов 1С не поддерживает рекурсию в чистом виде. В рамках этой статьи мы разберем несколько способов решения этой задачи, начиная от простых конструкций для консоли и заканчивая производительными методами для больших объемов данных.

Проблема использования NULL в иерархии

Типичная ошибка начинающих разработчиков при поиске корня — использование конструкции ЕСТЬ NULL. Важно понимать, что в системе 1С:Предприятие поле Родитель у элементов справочника никогда не содержит значение NULL. Если элемент находится в корне справочника, его родителем является пустая ссылка соответствующего типа.

Проанализируем ситуацию: когда мы пишем запрос и пытаемся проверить ДоговорыКонтрагентов.Родитель ЕСТЬ NULL, условие всегда будет ложным, и мы получим пустой результат или некорректные данные. Правильный подход — сравнение со значением ЗНАЧЕНИЕ(Справочник.ИмяСправочника.ПустаяСсылка).

Решение 1: Использование вложенных конструкций ВЫБОР

Если нам заранее известно максимальное количество уровней вложенности (например, не более 5), самым быстрым способом решения задачи в консоли запросов будет использование конструкции ВЫБОР КОГДА... ТОГДА. Рассмотрим этот метод по шагам.

Суть метода заключается в последовательной проверке поля Родитель на каждом уровне. Мы «поднимаемся» вверх, пока не встретим пустую ссылку.


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

Преимущества этого метода:

  1. Работает в любой стандартной консоли запросов без дополнительного кода.
  2. Легко читается при небольшом количестве уровней.
  3. Не требует создания временных таблиц.

Недостатки:

  1. Ограничение по глубине вложенности. Если появится элемент 6-го уровня, запрос вернет некорректный «корень».
  2. Снижение производительности при большом количестве уровней из-за множественных неявных соединений (LEFT JOIN), которые СУБД генерирует для каждого обращения через точку.

Решение 2: Использование временных таблиц для поэтапного подъема

Если мы хотим сделать запрос более структурированным и избежать длинных цепочек «через точку», мы можем использовать временные таблицы. Это особенно полезно, когда нужно получить не только корень, но и промежуточные данные.

Разберем логику: мы создаем временную таблицу, куда помещаем ссылку и её непосредственного родителя. Затем в следующей временной таблице мы соединяем первую таблицу саму с собой, заменяя родителя на родителя следующего уровня, если тот не пустой.


// Шаг 1: Получаем исходные данные
ВЫБРАТЬ
    Договоры.Ссылка КАК Ссылка,
    Договоры.Родитель КАК ТекущийРодитель
ПОМЕСТИТЬ ВТ_Уровень1
ИЗ
    Справочник.ДоговорыКонтрагентов КАК Договоры
ГДЕ
    Договоры.Ссылка В (&СписокСсылок);

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Поднимаемся на уровень выше
ВЫБРАТЬ
    ВТ.Ссылка КАК Ссылка,
    ВЫБОР
        КОГДА Родители.Родитель ЕСТЬ NULL ТОГДА ВТ.ТекущийРодитель
        КОГДА Родители.Родитель = ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка) ТОГДА ВТ.ТекущийРодитель
        ИНАЧЕ Родители.Родитель
    КОНЕЦ КАК ТекущийРодитель
ПОМЕСТИТЬ ВТ_Уровень2
ИЗ
    ВТ_Уровень1 КАК ВТ
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ДоговорыКонтрагентов КАК Родители
        ПО ВТ.ТекущийРодитель = Родители.Ссылка;

// И так далее для нужного количества уровней...

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

Решение 3: Метод транзитивного замыкания (для продвинутых задач)

Для случаев, когда глубина иерархии неизвестна или очень велика, а запрос должен работать максимально быстро, профессионалы используют метод транзитивного замыкания. Рассмотрим, в чем его суть.

В иерархических структурах 1С штатный поиск «В ИЕРАРХИИ» работает достаточно эффективно, но он направлен «вниз». Чтобы эффективно искать «вверх», иногда создают вспомогательные таблицы (или регистры сведения), где хранятся пары Элемент — Все его предки. Если такого регистра в конфигурации нет, построить его «на лету» в консоли запросов сложно, однако это стандарт индустрии для высоконагруженных систем.

Если же стоит задача найти корень один раз, можно использовать следующий алгоритм в консоли с постобработкой:

  1. Выбрать все уникальные родительские ссылки для искомых элементов (используя В ИЕРАРХИИ).
  2. Среди всех полученных предков найти те, у которых Родитель = ПустаяСсылка.
  3. Это и будут наши корни.

Использование СКД и продвинутых консолей

Проанализируем возможности современных инструментов. Если вы используете консоль запросов, встроенную в «Инструменты разработчика» или консоль на базе Системы компоновки данных (СКД), задача упрощается. В СКД можно настроить связь набора данных с самим собой по полю Родитель и Ссылка.

Выясним, как это помогает: СКД умеет автоматически вычислять иерархию и предоставлять функции для работы с ней. Например, можно использовать вычисляемые поля, которые будут обращаться к вышестоящим уровням. Однако для простой выборки в консоли запросов метод из Решения 1 остается самым популярным ввиду своей лаконичности.

Важные замечания по производительности

При написании запросов к иерархии следует помнить о следующих моментах:

Подводя итог, можно сказать, что для оперативной работы в консоли запросов использование конструкции ВЫБОР с проверкой на ЗНАЧЕНИЕ(...ПустаяСсылка) является оптимальным балансом между сложностью написания и результатом.

← На главную