Как получить вложенную таблицу в поле запроса 1С и правильно сформировать дерево значений

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

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

В данной статье мы разберем, как правильно связать две таблицы (Продукция и Запасы), почему обычное соединение может не подойти для построения дерева и какие инструменты платформы позволяют добиться нужного результата «строка + вложенный список».

Метод 1. Использование итогов в запросе и выгрузка в дерево значений

Самый простой и правильный способ с точки зрения платформы 1С — это использование конструкции ИТОГИ ПО. Многие начинающие разработчики пытаются использовать ЛЕВОЕ СОЕДИНЕНИЕ, но оно дублирует данные родительской строки для каждой строки потомка. Использование итогов позволяет сгруппировать данные и подготовить их для иерархического обхода.

Рассмотрим пример запроса, где мы связываем продукцию и ее запасы:


ВЫБРАТЬ
    Продукция.Ссылка КАК Продукция,
    Запасы.Номенклатура КАК Запас,
    Запасы.Количество КАК Количество
ИЗ
    Справочник.Продукция КАК Продукция
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Запасы КАК Запасы
    ПО Продукция.Ссылка = Запасы.Владелец
ИТОГИ ПО
    Продукция

Проанализируем этот подход. После выполнения такого запроса мы можем получить результат не просто плоским списком, а в виде готового объекта ДеревоЗначений. Для этого используется метод Выгрузить с параметром ОбходРезультатаЗапроса.ПоГруппировкам. Это исключает необходимость вручную писать циклы для создания узлов дерева.


РезультатЗапроса = Запрос.Выполнить();
Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
// Теперь в переменной 'Дерево' находится иерархическая структура

Метод 2. Программное построение дерева из таблицы значений

Иногда использование ИТОГИ невозможно или неудобно, если данные приходят из разных источников или требуют сложной предварительной обработки. В этом случае мы можем построить дерево «вручную». Чтобы этот процесс был быстрым, необходимо использовать индексацию таблиц.

Разберем алгоритм построения дерева из плоской таблицы ТЗ, где есть колонки Продукция и Запас:


// Создаем индексы для быстрого поиска
ТЗ.Индексы.Добавить("Продукция");

// Получаем уникальный список продукции
СписокПродукции = ТЗ.Скопировать(, "Продукция");
СписокПродукции.Свернуть("Продукция");

Для Каждого СтрПродукция Из СписокПродукции Цикл
    // Создаем родительский узел в дереве
    СтрокаДерева = ДеревоЗначений.Строки.Добавить();
    СтрокаДерева.Наименование = СтрПродукция.Продукция;
    
    // Ищем все запасы, относящиеся к этой продукции
    Отбор = Новый Структура("Продукция", СтрПродукция.Продукция);
    НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);
    
    Для Каждого СтрокаЗапас Из НайденныеСтроки Цикл
        // Добавляем подчиненные строки
        НоваяСтрокаЗапас = СтрокаДерева.Строки.Добавить();
        НоваяСтрокаЗапас.Наименование = СтрокаЗапас.Запас;
    КонецЦикла;
КонецЦикла;

Важный момент: при работе с табличными частями документов вместо НомерСтроки крайне рекомендуется использовать КлючСвязи. Это специальный реквизит (типа Число или УникальныйИдентификатор), который гарантирует стабильность связи между строками разных табличных частей, даже если строки будут пересортированы или удалены.

Метод 3. Вложенные таблицы в запросах к объектам

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

Посмотрим на пример запроса к документу:


ВЫБРАТЬ
    Реализация.Ссылка КАК Документ,
    Реализация.Товары.(
        Номенклатура,
        Количество
    ) КАК ТаблицаТоваров
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода

В данном случае поле ТаблицаТоваров в каждой строке результата будет содержать объект типа РезультатЗапроса. Его можно обойти через Выбрать() или выгрузить в таблицу значений. Это максимально приближено к тому, что хотел автор вопроса, но накладывает ограничение: данные должны физически храниться в табличных частях.

Метод 4. Агрегация строк через СКД

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

Выясним, как это настроить:

  1. В схеме компоновки создаем набор данных с запросом по продукции и запасам.
  2. Переходим на закладку Ресурсы.
  3. Для поля Запас пишем выражение: СоединитьСтроки(Массив(Запас), ", ").
  4. В настройках группируем только по Продукции.

В результате СКД сама схлопнет строки продукции и выведет все связанные запасы в одну текстовую строку, разделенную запятыми. Это решает проблему «лишних строк» в отчете.

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

При реализации связи таблиц через запросы всегда нужно помнить о производительности:

  1. Индексация временных таблиц: Если вы соединяете две временные таблицы (например, ВТ_Продукция и ВТ_Запасы), обязательно проиндексируйте поля связи во второй таблице. Без индекса СУБД будет выполнять вложенные циклы, что приведет к деградации производительности на больших объемах данных.
  2. Ключ связи: При программном добавлении строк в связанные табличные части всегда генерируйте уникальный КлючСвязи. Это избавит вас от ошибок, когда НомерСтроки меняется при интерактивном удалении строк пользователем.
  3. Обход результата: Старайтесь использовать встроенный метод Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам), так как он оптимизирован на уровне платформы и работает быстрее, чем ручное создание строк дерева в цикле.

Таким образом, хотя «вложенные таблицы» в произвольных запросах напрямую создать нельзя, комбинация Итогов, правильной структуры ДереваЗначений или возможностей СКД позволяет решить задачу любой сложности по иерархическому представлению данных.

← На главную