При разработке производственных отчетов в 1С одной из самых трудоемких задач является разузлование спецификаций. Когда дерево вложенности достигает 10, 15 или даже 20 уровней, классический рекурсивный алгоритм на встроенном языке начинает работать крайне медленно. Это происходит из-за огромного количества обращений к базе данных в цикле. Рассмотрим, как решить эту задачу изящно и максимально производительно с помощью Системы компоновки данных (СКД), используя механизм рекурсивной связи наборов данных.
Традиционный подход подразумевает написание функции, которая для каждой номенклатуры ищет её компоненты, а затем вызывает саму себя для каждого найденного узла. В системе компоновки данных заложен мощный механизм — связь наборов данных, который позволяет построить иерархию на уровне SQL-запросов, генерируемых платформой. Проанализируем ситуацию: если мы свяжем набор данных с самим собой, СКД будет итеративно выполнять запросы до тех пор, пока не достигнет самого нижнего уровня вложенности (листьев дерева) или не выполнится условие ограничения.
Основная сложность, с которой сталкиваются разработчики, заключается в том, что стандартные примеры в интернете часто показывают разузлование для одной конкретной спецификации, передаваемой через параметр. В реальных задачах (например, анализ плана производства) нам нужно разузловать сразу список спецификаций. Выясним, как это реализовать.
Для начала создадим схему компоновки данных и добавим Набор данных - запрос. Нам необходимо спроектировать запрос таким образом, чтобы он мог возвращать как «родительские» позиции, так и их состав. Разберем по шагам структуру запроса.
Посмотрим на пример текста запроса, который ляжет в основу нашего набора данных:
ВЫБРАТЬ
Т.Ссылка КАК СпецификацияРодитель,
Т.Номенклатура КАК Номенклатура,
Т.Количество КАК КоличествоНорматив,
Т.Спецификация КАК СпецификацияУзла,
1 КАК Коэффициент
ИЗ
Справочник.СпецификацииНоменклатуры.ИсходныеКомплектующие КАК Т
ГДЕ
Т.Ссылка В(&СписокСпецификаций)
Однако, чтобы механизм заработал для списка и правильно выстраивал иерархию, нам нужно добавить «корневые» элементы. Проанализируем решение: мы можем объединить данные из планов производства с данными самих спецификаций. Но более элегантный способ — использовать вложенный запрос или второй набор данных, который будет являться «точкой входа».
Перейдем на закладку «Связи наборов данных». Это сердце нашего решения. Именно здесь происходит магия разузлования. Нам нужно создать связь, где источником и приемником будет один и тот же набор данных (допустим, он называется НаборДанных1).
Настроим параметры связи следующим образом:
НаборДанных1НаборДанных1СпецификацияУзла (из источника) = СпецификацияРодитель (в приемнике).&СписокСпецификаций.Важный момент: Чтобы расчет количеств был корректным на каждом уровне, нам нужно передавать накопленный коэффициент с верхнего уровня на нижний. Рассмотрим подробнее, как это сделать через параметры связи.
Одной из главных проблем при разузловании является умножение количества компонента на количество продукции и на количества всех промежуточных полуфабрикатов. В СКД это решается через параметры связи.
Проанализируем настройку: в колонке «Параметры» связи наборов данных мы можем указать параметр, например, &КоличествоРодителя. В выражении для этого параметра мы передаем поле Количество (рассчитанное на текущем уровне). В самом тексте запроса мы должны использовать этот параметр:
ВЫБРАТЬ
Т.Ссылка КАК СпецификацияРодитель,
Т.Номенклатура,
Т.Количество * &КоличествоРодителя КАК Количество,
Т.Спецификация КАК СпецификацияУзла
ИЗ
Справочник.СпецификацииНоменклатуры.ИсходныеКомплектующие КАК Т
Таким образом, на каждый следующий уровень вложенности будет передаваться уже умноженное количество с предыдущего уровня. Это избавляет нас от необходимости писать сложные формулы в вычисляемых полях.
В реальных базах данных возможны ошибки, когда спецификация «зацикливается» (деталь А входит в состав детали Б, а Б — в состав А). Чтобы отчет не завис и не вызвал падение системы, необходимо добавить ограничение глубины рекурсии. Рассмотрим, как это реализовать:
Уровень.Уровень = 0.Уровень + 1.Уровень < 20.Это гарантирует, что даже при наличии циклов в данных, система остановится на 20-м уровне вложенности.
Если нам нужно строить отчет не просто по списку спецификаций, а в привязке к конкретным документам «План производства», выполним следующие действия:
Спецификация.В этом случае начальным выражением для рекурсии в НаборДанных_Разузлование будет выступать поле из первого набора. Проанализируем результат: СКД автоматически выполнит итерационный процесс для каждой строки из планов производства, объединив результаты в единое дерево.
Выясним, почему этот метод считается предпочтительным:
Таким образом, использование рекурсивных связей в СКД — это наиболее эффективный способ решения задачи разузлования спецификаций в современных конфигурациях 1С.