К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как заполнить дерево значений из запроса в 1С

Как заполнить дерево значений из запроса в 1С: метод Выгрузить с ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, обход строк, типовые ошибки и примеры кода.

Дерево значений в 1С — удобный способ показать пользователю иерархические данные: номенклатуру по группам, документы по контрагентам, остатки по складам. Самый быстрый способ заполнить такое дерево — выполнить запрос с итогами и выгрузить результат напрямую, без ручного обхода строк. Для этого у объекта «РезультатЗапроса» есть метод Выгрузить() с параметром обхода.

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

Ниже разобраны оба подхода — автоматическая выгрузка и ручной обход результата, требования к тексту запроса, типовые ошибки и способы проверить, что дерево заполнилось корректно.

Как устроено заполнение дерева из запроса

Механизм построен на связке двух объектов встроенного языка: РезультатЗапроса и ДеревоЗначений. Запрос формирует выборку с групповыми итогами, а метод Выгрузить() превращает эти итоги в строки дерева: каждая группировка становится родительской строкой, детальные записи — дочерними.

Важно понимать разницу между двумя режимами обхода. ПоГруппировкам строит дерево только по группировкам, указанным в секции ИТОГИ ПО. ПоГруппировкамСИерархией дополнительно учитывает иерархию самих данных — например, вложенность групп справочника «Номенклатура», если в запросе использована конструкция ИТОГИ ПО Поле ИЕРАРХИЯ или ТОЛЬКО ИЕРАРХИЯ.

Требования к тексту запроса

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

Также обратите внимание на поля выборки. В дерево попадут все поля, перечисленные в секции ВЫБРАТЬ, поэтому заранее убедитесь, что в дереве значений (или в реквизите формы с типом «ДеревоЗначений») созданы колонки с теми же именами. Расхождение имён не вызовет ошибку при автоматической выгрузке в новый объект, но при выгрузке в существующий реквизит формы лишние или отсутствующие колонки приведут к проблемам отображения.

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Остатки.Склад КАК Склад,

| Остатки.Номенклатура КАК Номенклатура,

| СУММА(Остатки.КоличествоОстаток) КАК Количество

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки

|СГРУППИРОВАТЬ ПО

| Остатки.Склад,

| Остатки.Номенклатура

|ИТОГИ

| СУММА(Количество)

|ПО

| Склад";

Быстрый способ: метод Выгрузить с обходом по группировкам

Если структура дерева совпадает со структурой итогов запроса, достаточно одной строки кода. Метод Выгрузить() сам создаст колонки, строки группировок и вложенные детальные записи:

РезультатЗапроса = Запрос.Выполнить();

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

Если дерево — это реквизит формы, присвойте результат через ЗначениеВРеквизитФормы:

ЗначениеВРеквизитФормы(Дерево, "ДеревоОстатков");

Признак корректного результата: в дереве на верхнем уровне находятся значения первого поля из секции ИТОГИ ПО, у каждой такой строки есть дочерние строки с детальными записями, а итоговые числовые поля (например, Количество) в родительских строках равны сумме дочерних.

Порядок действий
  1. 1
    Сформируйте запрос с секцией ИТОГИ ПО по нужным полям
  2. 2
    Выполните запрос и получите РезультатЗапроса
  3. 3
    Вызовите Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией)
  4. 4
    При необходимости передайте дерево в реквизит формы через ЗначениеВРеквизитФормы
  5. 5
    Проверьте уровни вложенности и итоги в родительских строках

Ручной обход выборки: когда автоматики недостаточно

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

ВыборкаГрупп = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

Пока ВыборкаГрупп.Следующий() Цикл

СтрокаГруппы = Дерево.Строки.Добавить();

ЗаполнитьЗначенияСвойств(СтрокаГруппы, ВыборкаГрупп);

ВыборкаДетали = ВыборкаГрупп.Выбрать();

Пока ВыборкаДетали.Следующий() Цикл

СтрокаДетали = СтрокаГруппы.Строки.Добавить();

ЗаполнитьЗначенияСвойств(СтрокаДетали, ВыборкаДетали);

КонецЦикла;

КонецЦикла;

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

Иерархия справочников: ИТОГИ ПО с ключевым словом ИЕРАРХИЯ

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

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

Сравнение вариантов

Выгрузить(ПоГруппировкамСИерархией)

Самый быстрый вариант: одна строка кода. Подходит, когда структура дерева совпадает с итогами запроса. Ограничение — нельзя изменить состав колонок и отфильтровать строки.

Ручной обход выборки

Полный контроль: вычисляемые поля, фильтрация, произвольная вложенность. Ограничение — больше кода и выше риск ошибки в рекурсии.

СКД с выводом в дерево

Подходит для отчётов: набор данных выводится как дерево настройками схемы. Ограничение — результат привязан к механизму отчётов, а не к произвольному ДеревоЗначений.

Типичные ошибки и как их избежать

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

Вторая частая проблема — отсутствие секции ИТОГИ ПО в запросе. В этом случае обход ПоГруппировкамСИерархией вернёт только детальные записи, и дерево окажется плоским. Третья ошибка — попытка присвоить дерево напрямую реквизиту формы типа «ДеревоЗначений» без ЗначениеВРеквизитФормы: на сервере реквизит формы — это данные формы, а не сам объект дерева.

Типичные ошибки
01
Вызов Выгрузить() без параметра — возвращается таблица значений, а не дерево, обращение к Строкам даёт ошибку
02
Нет секции ИТОГИ ПО в запросе — дерево получается плоским, без уровней
03
Прямое присвоение реквизиту формы вместо ЗначениеВРеквизитФормы — данные не отображаются
04
ИЕРАРХИЯ применена к неиерархическому полю — запрос падает с ошибкой или иерархии нет
05
Несовпадение имён колонок дерева и полей запроса при ручном обходе — ЗаполнитьЗначенияСвойств молча пропускает данные

Как проверить результат

После заполнения убедитесь, что дерево имеет ожидаемую структуру. Быстрые контрольные точки: количество строк верхнего уровня равно числу различных значений первого поля группировки; у каждой родительской строки есть дочерние строки; итоговые суммы в родителях сходятся с суммами дочерних строк. Программно это проверяется обходом Дерево.Строки и подсчётом Строки.Количество() на каждом уровне.

Для визуальной проверки выведите дерево на форму в элемент «Таблица формы» с отображением дерева и разверните узлы. Если узлы не раскрываются или данные дублируются — почти наверняка нарушен порядок полей в секции ИТОГИ ПО или выбран неверный тип обхода.

Контрольные точки

Как проверить результат

Количество строк верхнего уровня
Норма

Равно числу различных значений первого поля из ИТОГИ ПО

Тревожный признак

Одна строка или все записи на одном уровне — нет итогов в запросе

Дочерние строки у родителей
Норма

У каждой группировочной строки есть вложенные записи

Тревожный признак

Родители пустые — неверный тип обхода или детали не попали в выборку

Итоги в родительских строках
Норма

Сумма в родителе равна сумме дочерних строк

Тревожный признак

Итоги пустые или нулевые — поле итога не указано в секции ИТОГИ

FAQ

Можно ли заполнить дерево значений из запроса без секции ИТОГИ ПО?

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

Чем отличается ПоГруппировкам от ПоГруппировкамСИерархией?

ПоГруппировкам строит дерево только по полям из секции ИТОГИ ПО. ПоГруппировкамСИерархией дополнительно раскрывает вложенность иерархических данных, если в запросе использовано ИТОГИ ПО поле ИЕРАРХИЯ. Для неиерархических данных оба варианта дадут одинаковый результат.

Почему после Выгрузить дерево пустое, хотя запрос возвращает данные?

Проверьте, что запрос действительно выполнен и результат не пуст (РезультатЗапроса.Пустой()). Также убедитесь, что вы работаете с возвращённым значением метода Выгрузить, а не с ранее созданной пустой переменной дерева — метод создаёт новый объект, а не заполняет существующий.

Как вывести заполненное дерево на управляемую форму?

Создайте реквизит формы типа «ДеревоЗначений» с нужными колонками, перетащите его в элементы формы как таблицу с отображением дерева, а в коде после выгрузки из запроса вызовите ЗначениеВРеквизитФормы(Дерево, "ИмяРеквизита").

Можно ли заполнить дерево из нескольких запросов?

Да, но только ручным обходом: выполните запросы последовательно и добавляйте строки в общее дерево из каждой выборки. Автоматический метод Выгрузить работает только с одним результатом запроса за раз.

Как свернуть или развернуть все узлы дерева на форме программно?

Используйте методы элемента формы: Элементы.ИмяТаблицы.Свернуть(ИдентификаторСтроки) и Развернуть(ИдентификаторСтроки, СПодчиненными). Для обработки всех узлов обойдите коллекцию строк дерева через ПолучитьЭлементы() и примените метод к каждой строке.

Итог

Что важно запомнить

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