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

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

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

Решение 1: Использование связей наборов данных в СКД

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

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

  1. Создадим новый набор данных — запрос. В тексте запроса выберем данные из нашего регистра сведений:
    
    ВЫБРАТЬ
        Спецификации.ВыходноеИзделие КАК ВыходноеИзделие,
        Спецификации.ИсходнаяКомплектующая КАК ИсходнаяКомплектующая,
        Спецификации.Количество КАК Количество
    ИЗ
        РегистрСведений.СпецификацииНоменклатуры КАК Спецификации
    ГДЕ
        Спецификации.ВыходноеИзделие = &ВыходноеИзделие
    
  2. Перейдем на закладку "Связи наборов данных". Это ключевой этап. Здесь мы заставим СКД вызывать этот же запрос рекурсивно для каждой найденной комплектующей.
  3. Добавим новую связь:
    • Источник связи: НаборДанных1
    • Приемник связи: НаборДанных1
    • Условие связи: ИсходнаяКомплектующая (из источника) = ВыходноеИзделие (в приемнике)
    • Параметры: Укажем, что значение ИсходнаяКомплектующая должно передаваться в параметр запроса ВыходноеИзделие.
  4. В настройках отчета (закладка "Настройки") создадим группировку по полю ВыходноеИзделие, а вложенную в нее группировку — по полю ИсходнаяКомплектующая. Чтобы дерево было "бесконечным", используйте тип группировки "Иерархия" или просто вложенные детальные записи.

Таким образом, когда СКД находит комплектующую 1, она автоматически подставляет ее на место "Выходного изделия" и снова идет в регистр за ее составом (комплектующая 3, комплектующая 4), и так далее до самого нижнего уровня.

Решение 2: Построение иерархии через соединения в запросе

Если по каким-то причинам использование СКД невозможно (например, данные нужны в специфической обработке), мы можем применить метод "плоского" запроса с последовательными левыми соединениями. Этот способ подходит, если глубина вложенности ограничена (как в нашем примере — до 10 уровней).

Проанализируем структуру такого запроса. Мы берем основную таблицу и присоединяем ее к самой себе по условию ИсходнаяКомплектующая = ВыходноеИзделие. Рассмотрим пример для двух уровней:


ВЫБРАТЬ
    Уровень1.ВыходноеИзделие КАК Изделие,
    Уровень1.ИсходнаяКомплектующая КАК Узел_Лвл1,
    Уровень2.ИсходнаяКомплектующая КАК Узел_Лвл2
ИЗ
    РегистрСведений.СпецификацииНоменклатуры КАК Уровень1
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СпецификацииНоменклатуры КАК Уровень2
        ПО Уровень1.ИсходнаяКомплектующая = Уровень2.ВыходноеИзделие
ГДЕ
    Уровень1.ВыходноеИзделие = &ОсновноеИзделие

Чтобы получить 10 уровней, нам придется прописать 10 таких соединений. Главный минус этого подхода — громоздкость и резкое падение производительности при увеличении вложенности. Кроме того, такой запрос выдаст "плоскую" таблицу, которую потом придется программно преобразовывать в ДеревоЗначений. В качестве примера подобного преобразования можно использовать обработку для вывода результата запроса в дерево значений.

Проблема зацикливания и контроль данных

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

Рассмотрим методы предотвращения этой проблемы:

Решение 3: Программное построение дерева (через ДеревоЗначений)

Если требуется максимальный контроль, разберем алгоритм построения дерева в коде. Мы можем использовать временную таблицу, в которую будем порционно "докидывать" уровни.

  1. Выгружаем в ТаблицуЗначений первый уровень спецификации для выбранного изделия.
  2. Создаем объект ДеревоЗначений.
  3. Запускаем цикл Для каждого по полученным записям.
  4. Внутри цикла вызываем функцию, которая ищет компоненты для текущей строки. Это рекурсивная функция.

Пример структуры функции на языке 1С:


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

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

Выводы

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

← На главную