В практике разработки на платформе 1С:Предприятие часто возникает задача: на входе имеется ТаблицаЗначений, содержащая список групп (узлов) справочника, и ее необходимо дополнить всеми элементами, которые входят в эти группы на любом уровне вложенности. При этом важно сохранить контекстные данные из других колонок, например, признак качества или склад.
Основная сложность заключается в том, что язык запросов 1С имеет существенное ограничение: нельзя выполнить Левое Соединение (LEFT JOIN) одной таблицы с другой, используя условие В ИЕРАРХИИ в секции ПО. Система выдаст ошибку, так как это условие требует либо фиксированного значения, либо параметра-массива. Рассмотрим несколько эффективных стратегий решения этой задачи, от простых запросов до продвинутых механизмов СКД.
Это самый распространенный и понятный метод. Если объем данных в исходной таблице значений невелик (до нескольких тысяч групп), мы можем выгрузить ссылки на группы в массив и передать их в запрос как параметр. Проанализируем этот подход пошагово.
Сначала подготовим массив уникальных групп из нашей таблицы значений. Затем передадим его в запрос к справочнику. Главная хитрость здесь — сопоставить полученные элементы с их исходными группами-"родителями", чтобы проставить верное "Качество". Поскольку 1С не возвращает, по какой именно группе из массива был найден элемент в условии В ИЕРАРХИИ, нам придется либо делать это в цикле, либо использовать дополнительные механизмы.
Рассмотрим пример кода, где мы получаем все вложенные элементы:
// 1. Получаем массив уникальных групп из исходной ТЗ
МассивГрупп = ИсходнаяТЗ.ВыгрузитьКолонку("Номенклатура");
// 2. Формируем запрос для получения всех подчиненных элементов
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Родитель КАК Родитель
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В ИЕРАРХИИ(&МассивГрупп)
| И НЕ Номенклатура.ЭтоГруппа";
Запрос.УстановитьПараметр("МассивГрупп", МассивГрупп);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
После выполнения этого запроса мы получим плоский список всех элементов. Чтобы дополнить исходную ТЗ, нам нужно будет сопоставить эти элементы с данными о качестве. Если для всех групп качество одинаковое — задача тривиальна. Если разное — перейдем к более сложным методам.
Система компоновки данных — это, пожалуй, самый мощный и элегантный способ обойти ограничение на соединение по иерархии. В СКД реализован специальный механизм "Связи наборов данных", который поддерживает флаг "Иерархическая связь".
Разберем алгоритм настройки этого механизма:
ТаблицаЗначений). Назовем его НаборТЗ.Номенклатура. Назовем его НаборСправочник.НаборТЗ, поле Номенклатура.НаборСправочник, параметр (или поле) для фильтрации.ТаблицуЗначений.Этот метод позволяет системе автоматически выполнить рекурсивный поиск для каждой строки вашей таблицы и привязать найденные элементы к соответствующим значениям "Качества" из той же строки.
Если справочник огромный, а использование В ИЕРАРХИИ приводит к падению производительности (SQL Server может генерировать тяжелые планы запросов для этого оператора), мы можем применить метод последовательного получения уровней. Выясним причину эффективности этого метода: он использует индекс по полю Родитель.
Посмотрим на пример логики:
// Создаем временную таблицу, куда помещаем текущие группы для поиска
// В цикле ищем элементы, у которых Родитель входит в этот список
Пока Истина Цикл
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Родитель В (&СписокРодителей)";
// ... выполняем запрос, добавляем результат в итоговую ТЗ ...
// Если новых элементов не найдено - прерываем цикл
Если Результат.Пустой() Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Такой подход гарантирует контроль над нагрузкой и позволяет обрабатывать иерархию любой глубины без риска переполнения стека запроса.
Как упоминалось в обсуждении на форуме, можно использовать объект СхемаЗапроса. Если групп в исходной ТЗ немного, мы можем сформировать запрос, который объединяет несколько операторов ВЫБРАТЬ через ОБЪЕДИНИТЬ ВСЕ.
Для каждой строки исходной таблицы в текст запроса добавляется блок:
ВЫБРАТЬ Номенклатура.Ссылка, &Качество1 КАК Качество
ИЗ Справочник.Номенклатура КАК Номенклатура
ГДЕ Номенклатура.Ссылка В ИЕРАРХИИ(&Группа1)
Проанализируем ситуацию: этот метод хорош тем, что за один пакетный запрос мы получаем сразу готовую таблицу с проставленным качеством для каждого вложенного элемента. Однако помните об ограничении на количество объединений в одном запросе (обычно не рекомендуется более 256–512 UNION).
При работе с иерархическими данными в 1С важно придерживаться следующих правил:
Ссылка или Родитель в этих таблицах.И НЕ Номенклатура.ЭтоГруппа значительно сократит размер результирующей таблицы.ОбщегоНазначения.СформироватьЗапросПоИерархии() в вашей конфигурации. Типовые решения часто содержат готовые обертки для генерации правильного условия В ИЕРАРХИИ с учетом особенностей различных СУБД.Выбор конкретного метода зависит от ваших условий. Если важна простота кода — используйте Массив + В ИЕРАРХИИ. Если нужна максимальная производительность и корректное сопоставление данных — выбирайте СКД или Итерационный обход.