Как выбрать номенклатуру из вложенных папок (иерархии) в 1С:Предприятие?

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

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

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

Выясняем причину: почему метод Выбрать() не видит вложенные папки?

Рассмотрим исходный код, с которого часто начинают разработчики:

Выборка = Справочники.Номенклатура.Выбрать(ГруппаНоменклатуры);

При таком вызове метод Выбрать() принимает в качестве первого параметра родительскую группу. Однако «под капотом» платформы этот параметр интерпретируется как жесткий плоский фильтр: Родитель = ГруппаНоменклатуры.

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

---

Способ 1. Объектный метод ВыбратьИерархически()

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

Рассмотрим по шагам, как правильно написать код с использованием этого метода:

  1. Передаем в метод ссылку на родительскую группу.
  2. В цикле обхода выборки обязательно ставим условие проверки на группу. Так как метод выбирает абсолютно все узлы дерева (включая сами папки), нам нужно отсеять их с помощью свойства ЭтоГруппа, чтобы обрабатывать только конечные товары.

Пример программного кода:


// Укажем группу, из которой нужно получить все элементы
ГруппаНоменклатуры = Справочники.Номенклатура.НайтиПоНаименованию("Бытовая техника");

// Получаем иерархическую выборку
Выборка = Справочники.Номенклатура.ВыбратьИерархически(ГруппаНоменклатуры);

Пока Выборка.Следующий() Цикл
    // Исключаем из обработки сами папки
    Если Выборка.ЭтоГруппа Тогда
        Продолжить; 
    КонецЕсли;
    
    // Здесь выполняем полезную работу с элементом номенклатуры
    Сообщить("Товар: " + Выборка.Наименование);
КонецЦикла;

Важные нюансы метода ВыбратьИерархически():

---

Способ 2. Оптимальное решение через запрос и конструкцию В ИЕРАРХИИ

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

Для работы с вложенными папками в языке запросов 1С предусмотрен специальный оператор В ИЕРАРХИИ. Разберем пример правильного построения запроса:


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

// Устанавливаем ссылку на интересующую нас группу
Запрос.УстановитьПараметр("ГруппаНоменклатуры", ГруппаНоменклатуры);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Next() Цикл
    // Работаем со считанными данными
    Сообщить("Код: " + Выборка.Код + " | Товар: " + Выборка.Наименование);
КонецЦикла;

Почему этот способ предпочтительнее?

  1. Экономия ресурсов: Мы выбираем только нужные поля (Ссылка, Код, Наименование). Лишние реквизиты не запрашиваются.
  2. Фильтрация на стороне СУБД: Условие И НЕ Номенклатура.ЭтоГруппа отрабатывает прямо в базе данных. В память сервера приложений 1С передаются уже готовые плоские строки товаров, минуя служебные папки.

---

Как конструкция В ИЕРАРХИИ работает «под капотом» СУБД?

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

В реляционных базах данных таблицы справочников 1С хранятся по принципу Adjacency List (список смежности). Это значит, что у записи элемента есть только одна колонка — ссылка на его непосредственного родителя. СУБД изначально ничего не знает о глубокой структуре дерева и не может в один простой клик найти «всех потомков» группы.

Когда мы пишем в запросе 1С В ИЕРАРХИИ(&Группа), платформа выполняет сложную работу:

Важная рекомендация: Из-за сложной трансляции в SQL старайтесь избегать частого использования конструкции В ИЕРАРХИИ внутри циклов или в сложных соединениях виртуальных таблиц. Если вам нужно часто обращаться к иерархии, рассмотрите возможность кэширования связей или использования временных таблиц.

---

Альтернатива для отчетов: Иерархия в СКД (Системе компоновки данных)

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

Рассмотрим этот механизм:

  1. В схеме компоновки данных (СКД) напишите самый простой, плоский запрос, выбирающий номенклатуру без каких-либо условий по иерархии.
  2. Перейдите на вкладку «Настройки».
  3. Добавьте группировку по полю Номенклатура.
  4. В типе группировки вместо значения «Элементы» выберите «Иерархия» или «Только иерархия».

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

← На главную