При разработке отчетов и обработок часто возникает задача визуализировать данные в виде дерева: на верхнем уровне должны находиться группы (например, значения свойств или категории), а на подчиненном уровне — элементы номенклатуры, относящиеся к этой группе. При этом требуется, чтобы и названия групп, и наименования элементов отображались в одной и той же колонке таблицы или дерева значений.
Рассмотрим, почему стандартная выгрузка запроса не всегда решает эту задачу сразу и как правильно реализовать такое поведение в 1С.
Выясним причину проблемы. Когда мы пишем запрос с секцией ИТОГИ и выполняем выгрузку результата через Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам), платформа 1С формирует структуру колонок строго по списку выбранных полей. В итоговых строках верхнего уровня заполнено только поле группировки (например, Значение), а детальное поле Номенклатура остается пустым. В подчиненных строках детальных записей, наоборот, заполнено поле Номенклатура, а значение группировки не дублируется. В итоге на форме данные располагаются «лесенкой» в двух разных колонках. Запрос сам по себе не отвечает за визуальное объединение разнотипных данных в одну ячейку интерфейса.
Разберем основные способы решения данной задачи.
Этот способ является наиболее универсальным, гибким и прозрачным. Вместо прямой выгрузки результата запроса в дерево значений мы создаем структуру программно, объявляя колонку с составным типом данных (или произвольным типом), после чего последовательно обходим группировки и детальные записи.
Посмотрим на пример реализации:
// 1. Формируем и выполняем запрос с итогами
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗначенияСвойствОбъектов.Объект КАК Номенклатура,
| ЗначенияСвойствОбъектов.Значение КАК ЗначениеСвойства
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
|ГДЕ
| ЗначенияСвойствОбъектов.Объект ССЫЛКА Справочник.Номенклатура
| И ЗначенияСвойствОбъектов.Свойство = &СвойствоКатегория
|ИТОГИ ПО
| ЗначениеСвойства";
Запрос.УстановитьПараметр("СвойствоКатегория", СвойствоКатегория);
Результат = Запрос.Выполнить();
// 2. Создаем дерево значений с единой колонкой
Дерево = Новый ДеревоЗначений;
// Колонка должна вмещать как значения свойства, так и ссылки на номенклатуру
Дерево.Колонки.Добавить("Наименование");
Дерево.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
// 3. Выполняем иерархический обход по группировкам
ВыборкаГрупп = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаГрупп.Следующий() Цикл
СтрокаГруппы = Дерево.Строки.Добавить();
СтрокаГруппы.Наименование = ВыборкаГрупп.ЗначениеСвойства;
ВыборкаДеталей = ВыборкаГрупп.Выбрать();
Пока ВыборкаДеталей.Следующий() Цикл
СтрокаДетали = СтрокаГруппы.Строки.Добавить();
СтрокаДетали.Наименование = ВыборкаДеталей.Номенклатура;
КонецЦикла;
КонецЦикла;
// 4. Привязываем полученное дерево к элементу управления формы
ЭлементыФормы.ПолеДереваЗначений.Значение = Дерево;
ЭлементыФормы.ПолеДереваЗначений.СоздатьКолонки();
Разберем по шагам, что здесь происходит:
Наименование без жесткого ограничения по типу, что позволяет хранить в ней как значения свойств, так и элементы справочника.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам) возвращает верхний уровень иерархии (группировки по свойству).ВыборкаГрупп.Выбрать() получает детальные записи только для текущей группы.Наименование и для родительских, и для дочерних строк.Если требуется использовать метод прямой выгрузки Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам), можно переопределить значение детального поля для итоговых строк непосредственно в запросе с помощью агрегатной функции.
Проанализируем пример такого запроса:
ВЫБРАТЬ
ЗначенияСвойствОбъектов.Объект КАК Объект,
ЗначенияСвойствОбъектов.Значение КАК Значение
ИЗ
РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
ГДЕ
ЗначенияСвойствОбъектов.Объект ССЫЛКА Справочник.Номенклатура
И ЗначенияСвойствОбъектов.Свойство = &СвойствоКатегория
ИТОГИ
МАКСИМУМ(Значение) КАК Объект
ПО
Значение
Рассмотрим особенности этого решения:
ИТОГИ конструкция МАКСИМУМ(Значение) КАК Объект принудительно заполняет поле Объект значением свойства на уровне итоговых записей.Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам) колонка Объект будет содержать значение свойства в родительских строках и ссылку на номенклатуру в подчиненных строках.Значение в интерфейсе после выгрузки можно скрыть.Если данные уже выгружены стандартным образом в дерево значений, можно не модифицировать само дерево, а настроить визуальное отображение в элементе управления ТабличноеПоле:
Процедура ДеревоЗначенийПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Проверяем, является ли текущая строка группировкой
Если ДанныеСтроки.Строки.Количество() > 0 Тогда
// Подменяем текст ячейки номенклатуры значением свойства
ОформлениеСтроки.Ячейки.Номенклатура.Текст = Строка(ДанныеСтроки.Значение);
КонецЕсли;
КонецПроцедуры
В этом случае колонка Значение скрывается из видимости, а в колонку Номенклатура для группировочных строк визуально выводится наименование свойства.
Таким образом, для вывода иерархических данных в единую колонку оптимально использовать программный обход выборки запроса с заполнением дерева значений вручную либо переопределять значения итоговых полей в секции ИТОГИ.