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