Как правильно отсортировать Таблицу Значений с сохранением иерархии номенклатуры в 1С 7.7?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При формировании нестандартных отчетов в 1С:Предприятии 7.7 разработчики часто сталкиваются с необходимостью объединить данные за несколько периодов или из разных источников в единую Таблицу Значений (ТЗ). Однако стандартный метод ТЗ.Сортировать() при попытке упорядочить данные по покупателям и номенклатуре перемешивает элементы, ломая древовидную структуру каталога.

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

Почему обычная сортировка Таблицы Значений не строит иерархию?

Разберем, почему стандартные подходы не дают желаемого результата:

  1. Сортировка по ссылке: Вызов ТЗ.Сортировать("Покупатель,Номенклатура") сравнивает элементы по их строковому представлению (наименованию или коду). При этом родительские связи игнорируются, и все позиции выстраиваются в общий плоский алфавитный список.
  2. Сортировка по внутреннему значению: Конструкция ТЗ.Сортировать("Покупатель,*Номенклатура") выполняет сортировку по внутреннему 36-ричному идентификатору (ID) записи в базе данных. Этот идентификатор присваивается объектам хронологически в момент создания и не имеет отношения к иерархической структуре дерева справочника.
  3. Отсутствие групп в движениях регистров: Регистры накопления (например, «Продажи» в типовой конфигурации «Торговля и Склад») хранят записи только в разрезе конечных элементов. В плоской ТЗ, выгруженной из движений регистра, родительские группы физически отсутствуют. Соответственно, обычная сортировка упорядочивает только элементы, но не создает заголовки групп.

Решение 1: Добавление служебной колонки с полным наименованием или кодом

Самый простой штатный способ сохранить дерево подчинения внутри Таблицы Значений — добавить колонку с полным путем элемента в справочнике и выполнять сортировку по ней.

В платформе 1С 7.7 у объектов справочников есть метод ПолноеНаименование(), который возвращает строку со всеми вышестоящими уровнями иерархии, разделенными символом косой черты (/).

Рассмотрим по шагам реализацию этого подхода:

  1. Добавляем в Таблицу Значений дополнительную строковую колонку ПолныйПуть.
  2. При заполнении таблицы для каждой строки вычисляем полное наименование номенклатуры.
  3. Выполняем сортировку по колонкам покупателя и полного пути.

Посмотрим на пример кода:


ТЗ.НоваяКолонка("ПолныйПуть", "Строка");

ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    Если ПустоеЗначение(ТЗ.Номенклатура) = 0 Тогда
        ТЗ.ПолныйПуть = ТЗ.Номенклатура.ПолноеНаименование();
    КонецЕсли;
КонецЦикла;

ТЗ.Сортировать("Покупатель,ПолныйПуть");

При таком упорядочивании строки выстроятся по веткам дерева каталога, так как путь родительской папки будет являться префиксом для всех вложенных подгрупп и элементов (например: Бытовая техника, затем Бытовая техника/Холодильники, затем Бытовая техника/Холодильники/Модель 1).

Обратите внимание: Если в наименованиях самих папок или товаров уже содержится символ /, это может нарушить порядок сортировки. В таком случае надежнее использовать метод ПолныйКод(), если в справочнике включена уникальность кодов и задана фиксированная длина с лидирующими нулями.

Решение 2: Объединение периодов в едином штатном запросе

Если задача сводится к получению данных по нескольким произвольным периодам из регистра «Продажи», вместо выполнения трех запросов в цикле и последующего объединения в ТЗ эффективнее использовать один штатный объект Запрос. Платформа 1С 7.7 позволяет рассчитывать агрегатные функции по условию Когда и автоматически строит правильную иерархию.

Рассмотрим пример формирования такого запроса:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(ПродажиПоПериодам)
|Период С (МинДата) По (МаксДата);
|Покупатель = Регистр.Продажи.Покупатель;
|Номенклатура = Регистр.Продажи.Номенклатура;
|Сумма = Регистр.Продажи.ПродСтоимость;
|Док = Регистр.Продажи.ТекущийДокумент;
|
|Функция СуммаПериод1 = Сумма(Сумма) Когда (Док.ДатаДок >= ДатаНач1) И (Док.ДатаДок <= ДатаКон1);
|Функция СуммаПериод2 = Сумма(Сумма) Когда (Док.ДатаДок >= ДатаНач2) И (Док.ДатаДок <= ДатаКон2);
|Функция СуммаПериод3 = Сумма(Сумма) Когда (Док.ДатаДок >= ДатаНач3) И (Док.ДатаДок <= ДатаКон3);
|
|Группировка Покупатель Без Групп;
|Группировка Номенклатура Иерархия;
|"//}}ЗАПРОС
;

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка(1) = 1 Цикл
        // Обработка покупателя
        Пока Запрос.Группировка(2) = 1 Цикл
            // Вложенный обход номенклатуры с автоматическим выводом групп и элементов
            Если Запрос.ЭтоГруппа("Номенклатура") = 1 Тогда
                // Вывод заголовка группы
            Иначе
                // Вывод строки товара
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
КонецЕсли;

Такой способ полностью снимает проблему ручной сортировки, так как движок запросов 1С 7.7 берет на себя восстановление родительских веток и подсчет промежуточных итогов по уровням.

Решение 3: Использование компоненты 1С++ и класса «ИндексированнаяТаблица»

Если в проекте уже используется внешняя компонента 1С++, для сложных манипуляций с данными рекомендуется применять класс ИндексированнаяТаблица (ИТЗ). Он существенно быстрее стандартной ТЗ и поддерживает встроенную иерархическую группировку.

Разберем механизм работы с ИТЗ:

  1. В ИТЗ передается плоская таблица без промежуточных групп.
  2. При вызове метода группировки используется модификатор & перед именем поля справочника.
  3. ИТЗ автоматически подтягивает всех родителей и формирует корректное иерархическое дерево с нужными уровнями и итогами.

Посмотрим на пример использования:


ИТЗ = СоздатьОбъект("ИндексированнаяТаблица");
// Загружаем плоские данные из обычной ТЗ
ИТЗ.Загрузить(ТЗ);

// Группируем по покупателю и с иерархией по номенклатуре (&Номенклатура)
ИТЗ.Группировать("Покупатель,&Номенклатура", "Сумма1,Сумма2,Сумма3");

// Выполняем обход готового дерева
ИТЗ.ВыбратьСтроки();
Пока ИТЗ.ПолучитьСтроку() = 1 Цикл
    // Данные уже упорядочены по веткам иерархии с учетом родительских папок
КонецЦикла;

Использование ИТЗ избавляет от необходимости вручную формировать строковые ключи и восстанавливать недостающие папки в отчете.

← На главную