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

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

При разработке производственных отчетов в 1С одной из самых трудоемких задач является разузлование спецификаций. Когда дерево вложенности достигает 10, 15 или даже 20 уровней, классический рекурсивный алгоритм на встроенном языке начинает работать крайне медленно. Это происходит из-за огромного количества обращений к базе данных в цикле. Рассмотрим, как решить эту задачу изящно и максимально производительно с помощью Системы компоновки данных (СКД), используя механизм рекурсивной связи наборов данных.

Проблема производительности и концепция решения

Традиционный подход подразумевает написание функции, которая для каждой номенклатуры ищет её компоненты, а затем вызывает саму себя для каждого найденного узла. В системе компоновки данных заложен мощный механизм — связь наборов данных, который позволяет построить иерархию на уровне SQL-запросов, генерируемых платформой. Проанализируем ситуацию: если мы свяжем набор данных с самим собой, СКД будет итеративно выполнять запросы до тех пор, пока не достигнет самого нижнего уровня вложенности (листьев дерева) или не выполнится условие ограничения.

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

Шаг 1. Подготовка набора данных в СКД

Для начала создадим схему компоновки данных и добавим Набор данных - запрос. Нам необходимо спроектировать запрос таким образом, чтобы он мог возвращать как «родительские» позиции, так и их состав. Разберем по шагам структуру запроса.

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


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

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

Шаг 2. Настройка рекурсивной связи

Перейдем на закладку «Связи наборов данных». Это сердце нашего решения. Именно здесь происходит магия разузлования. Нам нужно создать связь, где источником и приемником будет один и тот же набор данных (допустим, он называется НаборДанных1).

Настроим параметры связи следующим образом:

  1. Источник связи: НаборДанных1
  2. Приемник связи: НаборДанных1
  3. Условие связи: СпецификацияУзла (из источника) = СпецификацияРодитель (в приемнике).
  4. Начальное выражение: Здесь мы указываем те спецификации, с которых начинается разузлование. Если мы хотим разузловать список из параметров, пишем &СписокСпецификаций.

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

Шаг 3. Расчет количества на всех уровнях вложенности

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

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


ВЫБРАТЬ
    Т.Ссылка КАК СпецификацияРодитель,
    Т.Номенклатура,
    Т.Количество * &КоличествоРодителя КАК Количество,
    Т.Спецификация КАК СпецификацияУзла
ИЗ
    Справочник.СпецификацииНоменклатуры.ИсходныеКомплектующие КАК Т

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

Шаг 4. Защита от зацикливания

В реальных базах данных возможны ошибки, когда спецификация «зацикливается» (деталь А входит в состав детали Б, а Б — в состав А). Чтобы отчет не завис и не вызвал падение системы, необходимо добавить ограничение глубины рекурсии. Рассмотрим, как это реализовать:

  1. Добавим в запрос набора данных поле Уровень.
  2. В начальном выражении (для корня) установим Уровень = 0.
  3. В связях наборов данных для приемника укажем выражение: Уровень + 1.
  4. В условии связи добавим ограничение: Уровень < 20.

Это гарантирует, что даже при наличии циклов в данных, система остановится на 20-м уровне вложенности.

Шаг 5. Особенности работы со списком продукции

Если нам нужно строить отчет не просто по списку спецификаций, а в привязке к конкретным документам «План производства», выполним следующие действия:

  1. Создадим НаборДанных_Планы, который выбирает продукцию и спецификации из документов.
  2. Создадим НаборДанных_Разузлование (как мы описывали выше).
  3. Свяжем их по полю Спецификация.

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

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

Выясним, почему этот метод считается предпочтительным:

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

← На главную