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

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

В практике разработки на платформе 1С часто возникает задача: получить данные, которые связаны не напрямую, а через иерархию. Типичный пример — справочник «Сопутствующие товары», где в шапке указана основная группа, а в табличной части перечислены другие группы или элементы, которые считаются сопутствующими. Сложность заключается в том, что нам нужно развернуть эти группы из табличной части до конечных элементов для всех записей справочника сразу. Давайте разберем, почему стандартный подход через В ИЕРАРХИИ не работает в лоб и какие существуют элегантные решения этой задачи.

Анализ проблемы: почему нельзя просто использовать В ИЕРАРХИИ

Основная техническая преграда заключается в особенностях языка запросов 1С. Оператор В ИЕРАРХИИ является мощным инструментом, но у него есть существенное ограничение: его невозможно использовать внутри условия связи ПО при соединении таблиц. Мы не можем написать конструкцию вида: ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура ПО Справочник.Номенклатура.Ссылка В ИЕРАРХИИ (ТЧ.СопутствующийТовар).

Если нам нужно получить данные только для одного конкретного элемента, проблема решается легко через передачу массива в параметр. Но когда стоит задача получить выборку для всего справочника (или большого списка документов), программисты часто совершают ошибку, используя запрос в цикле, что фатально сказывается на производительности системы. Проанализируем правильные подходы.

Решение №1: Использование Системы компоновки данных (СКД)

Рассмотрим самый «чистый» с точки зрения архитектуры 1С метод. СКД позволяет обходить ограничения языка запросов благодаря механизму связей наборов данных. Этот метод позволяет платформе самой сформировать необходимые подзапросы для работы с иерархией.

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

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

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

Решение №2: Метод «развертки» иерархии через временные таблицы

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

Проанализируем ситуацию: нам нужно знать для каждого элемента всех его родителей. Мы можем создать временную таблицу, в которой будут пары «Элемент — Родитель» для всех уровней вложенности. Посмотрим на пример реализации:


// 1. Помещаем во временную таблицу структуру справочника для всех уровней
ВЫБРАТЬ Ссылка, Ссылка КАК РодительВерхнегоУровня ПОМЕСТИТЬ ВТ_КартаИерархии ИЗ Справочник.Номенклатура
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Ссылка, Родитель ИЗ Справочник.Номенклатура ГДЕ Родитель <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Ссылка, Родитель.Родитель ИЗ Справочник.Номенклатура ГДЕ Родитель.Родитель <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
// ... и так далее до максимально возможного уровня вложенности (обычно 5-10)
;

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

Важный момент: Этот метод требует знания максимальной глубины иерархии. Однако он работает невероятно быстро, так как использует индексированные поля ссылок и простые соединения, которые СУБД оптимизирует гораздо лучше, чем рекурсивные условия В ИЕРАРХИИ.

Решение №3: Предварительная фильтрация через В ИЕРАРХИИ (ВЫБРАТЬ...)

Рассмотрим еще один вариант. Хотя мы не можем использовать иерархию в ПО, мы можем использовать её в блоке ГДЕ, если во временную таблицу предварительно собраны все «эталоны» из табличных частей.

Разберем алгоритм:

  1. Выбираем все СопутствующийТоварИлиГруппа из всех ТЧ справочника во временную таблицу ВТ_СписокГрупп.
  2. Делаем запрос к справочнику Номенклатура с условием ГДЕ Ссылка В ИЕРАРХИИ (ВЫБРАТЬ Ссылка ИЗ ВТ_СписокГрупп).

Но внимание: Этот метод вернет вам список ВСЕХ элементов, которые являются сопутствующими хотя бы для кого-то. Чтобы понять, к какой именно ГруппеНоменклатуры (из шапки) относится конкретный найденный элемент, вам все равно придется либо возвращаться к Методу №2, либо использовать СКД. Без этого связь «Владелец ТЧ — Найденный элемент» будет потеряна.

Рекомендации по производительности

Проанализируем нагрузку на систему. Если ваш справочник номенклатуры содержит сотни тысяч записей, а табличные части справочника сопутствующих товаров также активно заполнены, любые манипуляции с иерархией станут «тяжелыми». В таких случаях рекомендуется:

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

← На главную