При формировании сложных отчетов программным способом часто возникает необходимость сгруппировать данные по определенным периодам или категориям. Метод НачатьАвтогруппировкуСтрок() объекта ТабличныйДокумент кажется простым решением, однако новички часто сталкиваются с ситуацией, когда "плюсики" группировки не появляются, либо данные выводятся в ряд без ожидаемой иерархии. Разберем подробно, как работает этот механизм, проанализируем ошибки и рассмотрим правильные алгоритмы вывода.
Метод НачатьАвтогруппировкуСтрок() включает режим, при котором платформа анализирует параметр Уровень в методе Вывести(). Чтобы группировка сработала корректно, система должна понимать, какая строка является родительской, а какая — подчиненной. Рассмотрим основные правила:
N следуют строки с уровнем N + 1. Если все строки выводятся на одном уровне, никакой иерархии не возникнет.Рассмотрим наиболее надежный способ, предложенный в обсуждении. Проблема автора заключалась в том, что он пытался выводить заголовок группы (Период) внутри одного цикла по всем записям Таблицы Значений (ТЗ). Если в ТЗ одна и та же дата встречается несколько раз в разных строках, метод Вывести() с уровнем 1 будет вызываться повторно, создавая разрывы в группировке.
Для исправления ситуации проанализируем следующий алгоритм: сначала получим уникальный список периодов, а затем для каждого периода выведем все соответствующие ему детальные строки.
ТабДок.НачатьАвтогруппировкуСтрок();
// Шаг 1. Готовим список уникальных периодов для заголовков групп
ТЗ_Периоды = ТЗ.Скопировать();
ТЗ_Периоды.Свернуть("Период");
ТЗ_Периоды.Сортировать("Период Возр");
// Шаг 2. Обходим уникальные периоды
Для каждого СтрокаЗаголовок Из ТЗ_Периоды Цикл
// Выводим область заголовка группы (Уровень 1)
ОбластьЗаголовок.Параметры.Период = СтрокаЗаголовок.Период;
ТабДок.Вывести(ОбластьЗаголовок, 1);
// Шаг 3. Ищем все строки в исходной ТЗ, относящиеся к этому периоду
Отбор = Новый Структура("Период", СтрокаЗаголовок.Период);
НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);
Для каждого СтрокаДетали Из НайденныеСтроки Цикл
// Выводим детальные строки (Уровень 2)
ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, СтрокаДетали);
ТабДок.Вывести(ОбластьСтрока, 2);
КонецЦикла;
КонецЦикла;
ТабДок.ЗакончитьАвтогруппировкуСтрок();
В данном примере мы четко разделяем уровни: ОбластьЗаголовок выводится на уровне 1, а ОбластьСтрока — на уровне 2. Благодаря предварительной свертке (Свернуть) и поиску строк, мы гарантируем, что для каждой даты заголовок будет выведен ровно один раз, а все данные по этой дате окажутся "внутри" него.
Если создание копий таблиц кажется избыточным, можно воспользоваться методом контроля смены значения. Проанализируем этот подход. Нам необходимо предварительно отсортировать исходную таблицу по полю группировки.
ТЗ.Сортировать("Период Возр");
ТекущийПериод = '00010101';
ТабДок.НачатьАвтогруппировкуСтрок();
Для каждого Строка Из ТЗ Цикл
// Если период изменился — выводим новый заголовок
Если Строка.Период <> ТекущийПериод Тогда
ОбластьЗаголовок.Параметры.Период = Строка.Период;
ТабДок.Вывести(ОбластьЗаголовок, 1);
ТекущийПериод = Строка.Период;
КонецЕсли;
// Выводим детальные данные всегда на уровне 2
ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, Строка);
ТабДок.Вывести(ОбластьСтрока, 2);
КонецЦикла;
ТабДок.ЗакончитьАвтогруппировкуСтрок();
Этот метод более производителен для больших объемов данных, так как мы обходим таблицу всего один раз. Однако важно помнить: НачатьАвтогруппировкуСтрок() автоматически свяжет строки уровня 2 с последней выведенной строкой уровня 1.
Выясним причины, по которым даже при правильном коде группировка может не отображаться визуально:
ТабличныйДокумент установлено свойство ОтображатьСтруктуру = Истина. Без этого "плюсики" слева просто не появятся, хотя логически группировка будет создана.Дата, убедитесь, что время в датах обнулено (используйте НачалоДня()). Для 1С даты 01.01.2023 10:00:00 и 01.01.2023 12:00:00 — это разные значения, и они образуют разные группы.Как было отмечено в ходе обсуждения, многие задачи по группировке данных гораздо проще решаются через Систему Компоновки Данных (СКД). Если ваши условия отбора и группировки динамичны, рассмотрите вариант передачи вашей ТаблицыЗначений в СКД как внешний набор данных. В СКД иерархия строк настраивается в конструкторе за несколько секунд, и вам не придется вручную управлять методами Вывести() и следить за уровнями.
Если же использование ТабличногоДокумента напрямую неизбежно, придерживайтесь правила: сначала структура данных (сортировка), затем — вывод иерархии.