При разработке отчетов и обработок в системе «1С:Предприятие 8» часто возникает необходимость вывести данные иерархического справочника (например, Номенклатуры или Контрагентов) в удобном для пользователя виде. Если нам нужно, чтобы подчиненные элементы (строки-дети) располагались строго под своими родительскими группами, мы используем ключевое слово ИЕРАРХИЯ в секции УПОРЯДОЧИТЬ ПО. Однако, когда дело доходит до сортировки по нескольким полям одновременно, логика работы платформы становится неочевидной. Разберем детально, как устроен этот алгоритм «под капотом», и как ведут себя различные комбинации полей при упорядочивании.
Для начала проанализируем, как этот механизм реализован технически. В классическом языке SQL, который используют СУБД (MS SQL Server, PostgreSQL, Oracle), нет встроенного оператора ИЕРАРХИЯ в конструкции ORDER BY. СУБД возвращают плоские таблицы и умеют сортировать их только линейно.
Когда мы пишем запрос с использованием ключевого слова ИЕРАРХИЯ, происходит следующее:
Именно из-за этого возникает известный конфликт с ключевым словом ПЕРВЫЕ. Если мы попытаемся выбрать, например, ПЕРВЫЕ 10 элементов и упорядочить их по иерархии, СУБД сначала жестко обрежет выборку до 10 записей, а сервер приложений 1С попытается построить иерархию из того, что осталось. В результате дочерние элементы могут потерять своих родителей, а дерево окажется «разорванным».
Рассмотрим детально, как платформа 1С интерпретирует различные варианты написания инструкции УПОРЯДОЧИТЬ ПО при наличии нескольких полей.
Рассмотрим пример запроса:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Код КАК Код,
Номенклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
УПОРЯДОЧИТЬ ПО
Ссылка ИЕРАРХИЯ,
Код
Выясним, как платформа обрабатывает такую инструкцию. Алгоритм работает по следующим шагам:
Ссылка). Это гарантирует, что все дочерние элементы и подгруппы гарантированно окажутся ниже своих родительских групп.Код.Таким образом, мы получаем идеально выстроенное дерево, где на каждом уровне ветки отсортированы по коду.
Аналогично работает популярный методический прием для вывода папок выше элементов:
УПОРЯДОЧИТЬ ПО
Номенклатура.ЭтоГруппа ИЕРАРХИЯ,
Наименование
Здесь булево поле ЭтоГруппа не имеет физического родителя, поэтому платформа сначала группирует записи так, чтобы папки (значение ИСТИНА) шли выше элементов (значение ЛОЖЬ), а внутри этих групп выполняет алфавитную сортировку по полю Наименование.
Возьмем выражение: Упорядочить по Наименование ИЕРАРХИЯ, Код (где сортировка идет по иерархическому справочнику).
Здесь платформа сперва строит иерархическое дерево. Далее для каждого узла дерева (включая корневые элементы) все подчиненные элементы упорядочиваются сначала по первому указанному полю (Наименование), а при совпадении наименований — по второму полю (Код).
А теперь проанализируем ситуацию, когда ключевое слово ИЕРАРХИЯ указано не у первого поля сортировки. Например:
УПОРЯДОЧИТЬ ПО
Реквизит1,
Ссылка ИЕРАРХИЯ
В этом случае поведение платформы кардинально меняется:
Реквизит1. В результате данные разбиваются на сегменты, внутри каждого из которых значение Реквизит1 одинаково.Ссылка.Важное предупреждение: Такой подход таит в себе серьезную проблему «сломанного дерева». Если родительская группа имеет одно значение Реквизит1, а подчиненный ей элемент — другое, они попадут в разные сегменты сортировки. В результате дочерний элемент потеряет визуальную связь со своим родителем в итоговом выводе, и иерархическая структура будет разрушена.
Если же мы используем конструкцию типа Упорядочить по Наименование, Код ИЕРАРХИЯ, то иерархия будет строиться только для вложенных подгрупп (без учета конечных элементов), а сортировка на каждом уровне будет осуществляться по коду, тогда как элементы верхнего уровня будут упорядочены по наименованию.
Проанализируем ограничения, которые накладывает платформа 1С при использовании иерархического упорядочивания:
ИЕРАРХИЯ может быть применена только к тем полям, которые ссылаются на иерархические таблицы. Это могут быть иерархические справочники, планы счетов или планы видов характеристик. Попытка применить иерархическую сортировку к плоской таблице (например, к документам или регистру сведений напрямую) вызовет ошибку выполнения запроса.ИЕРАРХИЯ работает по тем же правилам, выстраивая цепочки подчинения. Однако проверка на ЭтоГруппа в этом случае не имеет смысла, так как для всех записей это свойство будет возвращать значение ЛОЖЬ.Поскольку построение дерева в оперативной памяти сервера приложений — это ресурсоемкая операция, использование УПОРЯДОЧИТЬ ПО ... ИЕРАРХИЯ в тяжелых запросах по большим таблицам (свыше десятков тысяч элементов) может существенно снизить производительность системы. Рассмотрим профессиональные альтернативы.
Вместо сортировки в секции УПОРЯДОЧИТЬ ПО мы можем использовать расчет итогов. Пример конструкции:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Штрихкод КАК Штрихкод
ИЗ
Справочник.Номенклатура КАК Номенклатура
ИТОГИ ПО
Ссылка ИЕРАРХИЯ
При обходе результатов такого запроса в коде на встроенном языке мы используем специальный метод обхода:
ВыборкаГруппировки = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Пока ВыборкаГруппировки.Следующий() Цикл
// Здесь мы получаем доступ к родительским группам и можем обходить их элементы
КонецЦикла;
Этот способ работает значительно эффективнее, так как платформа оптимизирует получение данных и выстраивание дерева на уровне работы с выборкой.
Если ваша задача — вывести иерархический список в отчет, настоятельно рекомендуется отказаться от сортировки ИЕРАРХИЯ непосредственно в тексте запроса. Вместо этого предоставьте построение дерева Системе компоновки данных.
В настройках структуры отчета СКД вместо обычной группировки добавьте группировку с типом «Иерархия» или «Иерархия групп и элементов». СКД компонует и выводит дерево гораздо быстрее, задействуя оптимизированные внутренние механизмы платформы, а также позволяет конечным пользователям гибко управлять сортировкой в пользовательских настройках без изменения схемы компоновки.