При разработке отчетов в системе 1С:Предприятие программисты часто сталкиваются с необходимостью создания таблиц с динамическим количеством колонок. Типичный пример — отчет, где в строках указаны статьи (например, налоги), а в колонках — периоды и организации. Основная сложность здесь заключается в том, что данные могут быть разреженными: для одного периода или организации данные есть, а для другого — нет. Если просто перебирать результат запроса, макет «съезжает», так как количество присоединенных областей в разных строках получается разным.
В этой статье мы подробно разберем, как реализовать стабильный вывод данных методом Присоединить, обеспечив жесткую структуру отчета независимо от наличия данных в конкретной ячейке.
Рассмотрим ситуацию, которую описывает автор темы: в первом периоде у нас есть данные по двум организациям из трех, а во втором — по всем трем. Если мы будем использовать цикл только по выборке данных, то в первой строке метод Присоединить будет вызван дважды, а во второй — трижды. В результате колонки второго периода окажутся под колонками первого, и итоговая таблица превратится в хаос.
Выясним причину: метод Присоединить добавляет область справа от уже выведенных. Для того чтобы вертикальные столбцы во всех строках совпадали, мы обязаны вызвать Присоединить одинаковое количество раз для каждой строки, передавая в параметры пустые значения или нули там, где данных нет.
Для реализации качественного отчета нам необходимо применить так называемый метод «Сетки». Разберем его по шагам.
Шаг 1. Получение полных списков измерений.
Прежде чем приступать к выводу, мы должны точно знать, какие колонки будут в отчете. Для этого сформируем массив или таблицу значений всех уникальных периодов и всех уникальных организаций, которые должны попасть в шапку.
Шаг 2. Подготовка данных для быстрого доступа.
Чтобы не делать поиск в таблице значений внутри вложенных циклов (что крайне медленно), проанализируем возможность использования объекта Соответствие или Структура. Мы можем выгрузить основной результат запроса в таблицу и проиндексировать её, либо собрать ключ вида Период + Организация + Налог.
Рассмотрим пример кода, который реализует правильный обход. Предположим, у нас уже выведена шапка отчета, и у нас есть массив МассивОрганизаций и МассивПериодов.
// 1. Сначала выводим левую фиксированную часть строки (Наименование налога)
Для Каждого ТекущийНалог Из СписокНалогов Цикл
ОбластьСтрокаНаименование = Макет.ПолучитьОбласть("Строка|Наименование");
ОбластьСтрокаНаименование.Параметры.НаименованиеНалога = ТекущийНалог.Значение;
ТабДок.Вывести(ОбластьСтрокаНаименование);
// 2. Вложенный цикл по периодам (колонки)
Для Каждого ТекущийПериод Из МассивПериодов Цикл
// 3. Вложенный цикл по организациям (под-колонки)
Для Каждого ТекущаяОрг Из МассивОрганизаций Цикл
ОбластьДанных = Макет.ПолучитьОбласть("Строка|ДанныеОрганизации");
// Пытаемся найти сумму для этой комбинации Налог + Период + Организация
ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("Налог", ТекущийНалог.Значение);
ПараметрыПоиска.Вставить("Период", ТекущийПериод);
ПараметрыПоиска.Вставить("Организация", ТекущаяОрг);
СтрокиДанных = ТаблицаРезультатов.НайтиСтроки(ПараметрыПоиска);
Если СтрокиДанных.Количество() > 0 Тогда
ОбластьДанных.Параметры.Сумма = СтрокиДанных[0].Сумма;
Иначе
// Критически важно: заполняем нулем, если данных нет
ОбластьДанных.Параметры.Сумма = 0;
КонецЕсли;
// Присоединяем область всегда, независимо от наличия данных
ТабДок.Присоединить(ОбластьДанных);
КонецЦикла;
КонецЦикла;
КонецЦикла;
В данном примере мы используем метод Присоединить для каждой ячейки данных. Благодаря тому, что циклы по организациям и периодам жестко привязаны к заранее подготовленным массивам, структура отчета будет идеальной.
Проанализируем более профессиональный подход. Вместо нескольких запросов и ручного поиска в таблице значений, мы можем использовать один запрос с предложением ИТОГИ. Это позволит нам использовать обход выборки по группировкам.
Пример структуры обхода:
ВыборкаНалог = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Налог"); — здесь мы делаем Вывести() левой части строки.ВыборкаПериод = ВыборкаНалог.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ"); — ключевое слово ВСЕ заставит систему 1С вернуть даже те периоды, в которых нет данных по текущему налогу.ВыборкаОрг = ВыборкаПериод.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Организация", "ВСЕ"); — аналогично получаем все организации.Использование параметра "ВСЕ" в методе Выбрать — это мощный инструмент, который автоматически решает проблему пустых колонок на уровне платформы.
При использовании метода Присоединить часто возникает визуальный дефект: границы между присоединенными областями могут выглядеть как двойные линии. Чтобы этого избежать, придерживайтесь следующих правил оформления макета:
Область(НачалоСтроки, НачалоКолонки, КонецСтроки, КонецКолонки) и свойство ГраницаСнизу, ГраницаСправа и т.д.Важно упомянуть, что ручной вывод макета через Присоединить — это трудоемкий процесс. В современной разработке на платформе 8.3 для таких задач рекомендуется использовать СКД с типом вывода «Таблица».
В СКД достаточно перетащить «Налоги» в строки, а «Период» и «Организацию» в колонки. Система автоматически выполнит соединение данных, создаст эталонную сетку колонок и заполнит пустые значения. Это экономит время разработчика и снижает вероятность ошибок при верстке макета.
Однако, если требования к оформлению специфичны (например, сложная многоуровневая шапка с объединенными ячейками, которые нельзя реализовать в СКД), метод Присоединить остается единственным надежным инструментом программиста.