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

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

Как в запросе 1С 8 вывести уровень иерархии

Как в запросе 1С 8 вывести уровень иерархии: функция Уровень(), итоги по иерархии, построитель дерева, типичные ошибки и примеры кода для отчетов.

Задача вывести уровень вложенности элемента в запросе возникает при работе с иерархическими справочниками (номенклатура, подразделения, статьи затрат), планами счетов и любыми древовидными структурами. В языке запросов 1С 8 для этого есть встроенная функция Уровень(), но у неё есть важное ограничение: она работает только внутри конструкции итогов по иерархии, а не как обычное вычисляемое поле.

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

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

Два сценария: уровень строки итогов и уровень элемента справочника

Прежде чем писать запрос, определите, что именно нужно получить. Уровень строки результата — это номер уровня группировки в иерархических итогах: корневые группы имеют уровень 1, их дочерние элементы — 2 и так далее. Это свойство строки выборки, а не данные самого элемента.

Уровень элемента справочника — это глубина вложенности конкретного объекта в дереве: например, группа «Товары» — уровень 1, «Товары/Электроника» — уровень 2, «Товары/Электроника/Телефоны» — уровень 3. Это характеристика самого элемента, и язык запросов не хранит её в готовом виде — её нужно вычислять.

Маршрут решения

Какой подход выбрать

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

Функция Уровень() в итогах по иерархии

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

ВЫБРАТЬ

Номенклатура.Ссылка КАК Ссылка,

Номенклатура.Наименование КАК Наименование

ИЗ

Справочник.Номенклатура КАК Номенклатура

ИТОГИ

Уровень() КАК УровеньГруппировки

ПО

Ссылка ИЕРАРХИЯ

Ключевые моменты синтаксиса: агрегатное выражение Уровень() указывается после слова ИТОГИ, а группировочное поле дополняется ключевым словом ИЕРАРХИЯ. Без ИЕРАРХИЯ запрос вернет только плоские итоги, и уровень теряет смысл — все записи будут на одном уровне.

Обход результата выполняется с указанием типа обхода ПоГруппировкамСИерархией:

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

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

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

Сообщить(Выборка.УровеньГруппировки); // или Выборка.Уровень()

КонецЦикла;

Вычисление уровня элемента соединением таблицы с собой

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

ВЫБРАТЬ

Спр.Ссылка КАК Ссылка,

ВЫБОР

КОГДА Родитель1.Ссылка ЕСТЬ NULL ТОГДА 1

КОГДА Родитель2.Ссылка ЕСТЬ NULL ТОГДА 2

КОГДА Родитель3.Ссылка ЕСТЬ NULL ТОГДА 3

ИНАЧЕ 4

КОНЕЦ КАК УровеньВложенности

ИЗ

Справочник.Номенклатура КАК Спр

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Родитель1

ПО Спр.Родитель = Родитель1.Ссылка

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Родитель2

ПО Родитель1.Родитель = Родитель2.Ссылка

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Родитель3

ПО Родитель2.Родитель = Родитель3.Ссылка

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

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

Вывод уровня в отчете на СКД

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

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

Порядок вывода дерева в отчете СКД
  1. 1
    В наборе данных напишите запрос по иерархической таблице без ручного вычисления уровня
  2. 2
    В настройках СКД добавьте группировку по полю ссылки и установите тип группировки «Иерархия»
  3. 3
    Для вывода уровня колонкой добавьте ресурс с выражением Уровень()
  4. 4
    Проверьте отчет на данных с глубиной не менее трех уровней
  5. 5
    При необходимости настройте условное оформление по значению уровня

Альтернатива: обход дерева в коде с подсчетом уровня

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

Процедура ОбойтиУровень(Родитель, Уровень, СоответствиеСтрок)

Строки = СоответствиеСтрок.Получить(Родитель);

Если Строки = Неопределено Тогда

Возврат;

КонецЕсли;

Для Каждого Строка Из Строки Цикл

// Строка.Уровень = Уровень — дальнейшая обработка

ОбойтиУровень(Строка.Ссылка, Уровень + 1, СоответствиеСтрок);

КонецЦикла;

КонецПроцедуры

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

Сравнение способов получения уровня

Уровень() в ИТОГИ ПО ... ИЕРАРХИЯ

Подходит для отчетов и иерархических выборок; не дает уровень элемента в плоской таблице

Соединения по Родитель

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

Обход в коде

Максимальная гибкость и неограниченная глубина; требует защиты от зацикливания и больше кода

Типичные ошибки и проверка результата

Самая частая ошибка — попытка написать Уровень() в секции ВЫБРАТЬ обычного запроса. Конструктор запросов и компилятор выдадут ошибку, потому что функция определена только в контексте итогов. Вторая типичная проблема — забытое слово ИЕРАРХИЯ после поля группировки: запрос выполнится, но все записи окажутся на одном уровне.

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

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

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

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

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

Значения уровня на тестовых данных
Норма

Корневая группа — 1, вложенные — 2, 3 и далее по фактической структуре

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

Все строки имеют одинаковый уровень или уровень не соответствует дереву

Поведение на глубоких ветках
Норма

Самый глубокий элемент получает корректный максимальный уровень

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

Элементы глубже лимита соединений «залипают» на одном значении

Итоги в отчете СКД
Норма

Суммы по группам равны сумме детальных записей

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

Итоги расходятся — вероятно, неверный тип группировки или дубли строк

FAQ

Можно ли использовать Уровень() в обычной выборке без ИТОГИ?

Нет. Функция Уровень() определена только в контексте итогов по иерархии. Для плоской таблицы глубину вычисляют соединениями по полю Родитель или в коде после выполнения запроса.

Почему запрос с ИТОГИ ПО ... ИЕРАРХИЯ возвращает все строки на одном уровне?

Чаще всего пропущено ключевое слово ИЕРАРХИЯ после поля группировки либо выборка обходится методом ПоГруппировкам вместо ПоГруппировкамСИерархией. Проверьте оба места.

Как получить уровень для плана счетов, где нет иерархии по родителю?

У планов счетов вложенность задается субсчетами, а не полем Родитель. Уровень определяют по связи счета со счетом-родителем через реквизит Родитель, если он есть в конфигурации, либо вычисляют в коде по структуре субсчетов.

Как ограничить глубину вывода дерева, например только двумя уровнями?

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

Влияет ли пометка удаления группы на уровень её подчиненных элементов?

Физически структура родителей не меняется, поэтому вычисленный уровень останется прежним. Если помеченные группы не должны попадать в отчет, добавьте в запрос отбор по ПометкаУдаления = ЛОЖЬ для всех соединяемых таблиц, иначе дерево будет содержать «мертвые» ветки.

Что быстрее: соединения по Родитель или обход в коде?

На небольших справочниках разница незаметна. На больших таблицах множественные соединения увеличивают нагрузку на СУБД, а обход в коде выполняется в памяти после одного запроса. Для очень крупных иерархий обычно выбирают выгрузку пар «элемент — родитель» и обход в коде.

Итог

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

Уровень строки иерархии дает функция Уровень() в конструкции ИТОГИ ПО ... ИЕРАРХИЯ и одноименный метод выборки. Глубину конкретного элемента в плоской таблице вычисляют соединениями по Родитель с оглядкой на максимальную глубину или обходом дерева в коде с защитой от циклов. Проверяйте результат на тестовом дереве известной структуры.