Как найти самого верхнего родителя или ближайшего родителя с заполненным значением в запросе 1С

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

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

Способ 1. Использование конструкции ВЫБОР КОГДА (Ограниченная вложенность)

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


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

Выясним причину популярности этого метода: он работает быстро и выполняется «одним выстрелом» на стороне сервера БД. Однако у него есть существенный минус — ограничение вложенности. Если в справочнике появится 11-й уровень, запрос вернет некорректные данные. Этот метод хорош для простых отчетов, но не подходит для гибких систем.

Способ 2. Получение иерархии через ИТОГИ ПО Ссылка ИЕРАРХИЯ

Рассмотрим более продвинутый метод, который использует встроенные механизмы платформы 1С для работы с деревьями. Платформа умеет самостоятельно достраивать иерархические связи, если мы укажем ключевое слово ИЕРАРХИЯ в блоке итогов. Разберем, как это работает на практике:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.СхемаЦТЗ КАК СхемаЦТЗ
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка = &Ссылка
ИТОГИ ПО
    Ссылка ИЕРАРХИЯ

После выполнения такого запроса мы получаем выборку, в которой записи идут от корня к искомому элементу. Проанализируем ситуацию: первая запись в Выборка будет соответствовать самому верхнему родителю. Это позволяет нам программно получить всю цепочку предков, не зная заранее глубину вложенности. Чтобы найти ближайшее заполненное значение, мы можем просто обходить выборку и сохранять последнее встреченное непустое значение СхемаЦТЗ.

Способ 3. Комбинированный метод (Запрос + Рекурсивная обработка)

Зачастую нам нужно получить данные не по одному элементу, а по всему каталогу сразу (например, для формирования сложного отчета). В этом случае использование итогов по всему справочнику может быть избыточным. Рассмотрим алгоритм, который сочетает эффективность запроса и гибкость программного кода.

Шаг 1. Подготовка данных в запросе. Выгрузим плоскую таблицу всех элементов и их непосредственных родителей во временную таблицу или ТаблицаЗначений.


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

Шаг 2. Программный поиск с использованием рекурсии. Напишем функцию, которая будет «подниматься» по родителям до тех пор, пока не найдет заполненное значение нужного нам реквизита.


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

Важный момент: чтобы избежать многократных запросов к базе внутри цикла (проблема 1+N), мы предварительно выгружаем весь справочник в ТаблицаЗначений и работаем с ней методом Найти(). Это значительно ускоряет выполнение задачи.

Способ 4. Использование СКД и связей наборов данных

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

  1. Создадим Набор данных - запрос, который выбирает номенклатуру и её непосредственную схему.
  2. Вкладка Связи наборов данных: свяжем этот набор с самим собой.
  3. В поле «Источник связи» укажем Родитель, в поле «Приемник» — Ссылка.
  4. Установим флаг Связь по иерархии.

Этот механизм заставит СКД рекурсивно запрашивать родителей для каждой строки. Чтобы получить «первое заполненное значение», в выражении ресурсов можно использовать функции СКД, такие как ВычислитьВыражение, анализируя массив значений всех уровней иерархии.

Сводная таблица методов

Проанализируем, какой метод лучше выбрать в зависимости от условий:

  1. Вложенный ВЫБОР КОГДА — если вложенность жестко ограничена (например, уровни регионов: Страна-Область-Город).
  2. Запрос с ИТОГИ ПО ИЕРАРХИЯ — если нужно быстро найти предков для одного или нескольких конкретных элементов.
  3. Рекурсия по Таблице Значений — лучший выбор для массовой обработки данных в обработках.
  4. Связи в СКД — идеальный вариант для сложных отчетов с иерархическими итогами.

Помните, что при работе с иерархией важно следить за производительностью. Использование метода Объект.Родитель.Родитель.Реквизит в цикле является «антипаттерном», так как каждое обращение через точку к родителю порождает отдельный SQL-запрос. Всегда старайтесь получать необходимые данные заранее одним запросом.

← На главную