Как в 1С объединить группировки и детальные записи в одну иерархическую колонку дерева значений?

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

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

Рассмотрим, почему стандартная выгрузка запроса не всегда решает эту задачу сразу и как правильно реализовать такое поведение в 1С.

Выясним причину проблемы. Когда мы пишем запрос с секцией ИТОГИ и выполняем выгрузку результата через Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам), платформа 1С формирует структуру колонок строго по списку выбранных полей. В итоговых строках верхнего уровня заполнено только поле группировки (например, Значение), а детальное поле Номенклатура остается пустым. В подчиненных строках детальных записей, наоборот, заполнено поле Номенклатура, а значение группировки не дублируется. В итоге на форме данные располагаются «лесенкой» в двух разных колонках. Запрос сам по себе не отвечает за визуальное объединение разнотипных данных в одну ячейку интерфейса.

Разберем основные способы решения данной задачи.

Способ 1. Программное построение дерева значений через обход выборки

Этот способ является наиболее универсальным, гибким и прозрачным. Вместо прямой выгрузки результата запроса в дерево значений мы создаем структуру программно, объявляя колонку с составным типом данных (или произвольным типом), после чего последовательно обходим группировки и детальные записи.

Посмотрим на пример реализации:


// 1. Формируем и выполняем запрос с итогами
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЗначенияСвойствОбъектов.Объект КАК Номенклатура,
    |	ЗначенияСвойствОбъектов.Значение КАК ЗначениеСвойства
    |ИЗ
    |	РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
    |ГДЕ
    |	ЗначенияСвойствОбъектов.Объект ССЫЛКА Справочник.Номенклатура
    |	И ЗначенияСвойствОбъектов.Свойство = &СвойствоКатегория
    |ИТОГИ ПО
    |	ЗначениеСвойства";

Запрос.УстановитьПараметр("СвойствоКатегория", СвойствоКатегория);
Результат = Запрос.Выполнить();

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

// 3. Выполняем иерархический обход по группировкам
ВыборкаГрупп = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаГрупп.Следующий() Цикл
    
    СтрокаГруппы = Дерево.Строки.Добавить();
    СтрокаГруппы.Наименование = ВыборкаГрупп.ЗначениеСвойства;
    
    ВыборкаДеталей = ВыборкаГрупп.Выбрать();
    Пока ВыборкаДеталей.Следующий() Цикл
        
        СтрокаДетали = СтрокаГруппы.Строки.Добавить();
        СтрокаДетали.Наименование = ВыборкаДеталей.Номенклатура;
        
    КонецЦикла;
    
КонецЦикла;

// 4. Привязываем полученное дерево к элементу управления формы
ЭлементыФормы.ПолеДереваЗначений.Значение = Дерево;
ЭлементыФормы.ПолеДереваЗначений.СоздатьКолонки();

Разберем по шагам, что здесь происходит:

  1. Мы создаем дерево значений с колонкой Наименование без жесткого ограничения по типу, что позволяет хранить в ней как значения свойств, так и элементы справочника.
  2. Метод Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам) возвращает верхний уровень иерархии (группировки по свойству).
  3. Вложенный метод ВыборкаГрупп.Выбрать() получает детальные записи только для текущей группы.
  4. Мы заполняем одну и ту же колонку Наименование и для родительских, и для дочерних строк.

Способ 2. Подмена поля на уровне секции «ИТОГИ» в тексте запроса

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

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


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

Рассмотрим особенности этого решения:

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

Способ 3. Использование события табличного поля «ПриВыводеСтроки» (Обычные формы)

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


Процедура ДеревоЗначенийПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    
    // Проверяем, является ли текущая строка группировкой
    Если ДанныеСтроки.Строки.Количество() > 0 Тогда
        // Подменяем текст ячейки номенклатуры значением свойства
        ОформлениеСтроки.Ячейки.Номенклатура.Текст = Строка(ДанныеСтроки.Значение);
    КонецЕсли;
    
КонецПроцедуры

В этом случае колонка Значение скрывается из видимости, а в колонку Номенклатура для группировочных строк визуально выводится наименование свойства.

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

← На главную