Как реализовать вывод данных в колонки макета вместо строк (кросс-таблица) без использования СКД?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В практике разработки на платформе 1С часто возникает задача представить данные не в виде простого списка, а в виде кросс-таблицы (матрицы). Типичный пример — отчет по продажам, где в строках указаны товары, а в колонках — даты. Хотя Система Компоновки Данных (СКД) решает эту задачу автоматически, иногда условия задачи требуют реализации через обычный макет и программный вывод. Разберем подробно, как это сделать, используя методы Вывести() и Присоединить().

Принцип работы кросс-отчета в 1С

Для того чтобы данные «развернулись» по горизонтали, нам необходимо отойти от линейного вывода строк. Основная сложность заключается в том, что для каждого товара (строки) нам нужно сопоставить конкретное значение с конкретной датой (колонкой). Если просто перебирать результат запроса, мы получим «лесенку». Чтобы этого избежать, мы применим алгоритм вложенных выборок с использованием итогов в запросе.

Шаг 1: Подготовка запроса с итогами

Первым делом проанализируем запрос. Чтобы система понимала структуру будущей таблицы, в запросе обязательно должны быть указаны итоги по тем полям, которые станут строками и колонками. Рассмотрим пример запроса для документов заказа:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	ЗаказПокупателяТовары.Номенклатура КАК Номенклатура,
|	НАЧАЛОПЕРИОДА(ЗаказПокупателяТовары.Ссылка.Дата, ДЕНЬ) КАК Дата,
|	ЗаказПокупателяТовары.Количество КАК Количество,
|	ЗаказПокупателяТовары.Номенклатура.Код КАК Код
|ИЗ
|	Документ.ЗаказПокупателя.Товары КАК ЗаказПокупателяТовары
|ГДЕ
|	ЗаказПокупателяТовары.Ссылка.Дата МЕЖДУ &НачДата И &КонДата
|УПОРЯДОЧИТЬ ПО
|	Дата,
|	Номенклатура
|ИТОГИ
|	СУММА(Количество)
|ПО
|	ОБЩИЕ,
|	Дата,
|	Номенклатура";

Обратите внимание на секцию ИТОГИ. Группировка по полю Дата позволит нам сформировать шапку колонок, а группировка по Номенклатура — строки отчета.

Шаг 2: Формирование шапки колонок

После выполнения запроса нам нужно сначала вывести заголовок и все уникальные даты в одну строку. Для этого мы создадим первую выборку по группировке «Дата». Выясним, как правильно использовать метод Присоединить().


РезультатЗапроса = Запрос.Выполнить();

// Получаем области из макета
ОбластьШапкаЛево = Макет.ПолучитьОбласть("Шапка|Товар");
ОбластьШапкаКолонка = Макет.ПолучитьОбласть("Шапка|Дата");

// Выводим статичную часть шапки (Код, Наименование)
ТабДок.Вывести(ОбластьШапкаЛево);

// Выбираем только уникальные даты для формирования колонок
ВыборкаДатыШапки = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Дата");
Пока ВыборкаДатыШапки.Следующий() Цикл
    ОбластьШапкаКолонка.Параметры.ДатаШапки = Формат(ВыборкаДатыШапки.Дата, "ДФ=dd.MM.yy");
    ТабДок.Присоединить(ОбластьШапкаКолонка);
КонецЦикла;

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

Шаг 3: Вывод строк данных с использованием параметра ВСЕ

Теперь переходим к самому сложному — выводу строк товаров так, чтобы количество попало точно под свою дату. Если мы просто запустим цикл по товарам, а внутри него — цикл по датам, мы столкнемся с проблемой: если товар не продавался в определенный день, колонка «съедет» влево.

Проанализируем решение этой проблемы. Платформа 1С предоставляет мощный инструмент — параметр "ВСЕ" (или "ALL") в методе Выбрать(). Этот параметр заставляет выборку возвращать записи для всех значений группировки, которые есть в общем результате запроса, даже если для конкретной номенклатуры данных на эту дату нет. В таких случаях значение ресурса (Количество) будет равно NULL.


// Получаем области строк
ОбластьСтрокаЛево = Макет.ПолучитьОбласть("Строка|Товар");
ОбластьСтрокаДанные = Макет.ПолучитьОбласть("Строка|Дата");

// Основной цикл по товарам (строкам)
ВыборкаНоменклатура = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Номенклатура");
Пока ВыборкаНоменклатура.Следующий() Цикл
    
    // Заполняем код и наименование
    ОбластьСтрокаЛево.Параметры.Заполнить(ВыборкаНоменклатура);
    ТабДок.Вывести(ОбластьСтрокаЛево);
    
    // Вложенный цикл по датам для ЭТОГО товара
    // Используем параметр "ВСЕ", чтобы пройти по всем датам, которые были в шапке
    ВыборкаДатаДанные = ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Дата", "ВСЕ");
    
    Пока ВыборкаДатаДанные.Следующий() Цикл
        // Если данных на дату нет, выводим 0 вместо пустоты
        КолВо = ?(ВыборкаДатаДанные.Количество = NULL, 0, ВыборкаДатаДанные.Количество);
        ОбластьСтрокаДанные.Параметры.Количество = КолВо;
        
        // Присоединяем ячейку в ту же строку, где вывели Товар
        ТабДок.Присоединить(ОбластьСтрокаДанные);
    КонецЦикла;
    
КонецЦикла;

Шаг 4: Использование пересечений областей (Продвинутый метод)

Рассмотрим более профессиональный подход, который часто используется в сложных отчетах. Вместо того чтобы полагаться только на Присоединить(), можно использовать именование областей макета по горизонтали и вертикали. В макете создаются горизонтальная секция Строка и вертикальная секция Колонка.

Метод Макет.ПолучитьОбласть("Строка|Колонка") позволяет получить область на их пересечении. Это гарантирует, что формат ячейки будет в точности соответствовать задуманному дизайну. Посмотрим на алгоритм:

  1. Определяем в макете горизонтальную область (например, с именем СекцияСтрока) и вертикальную (например, СекцияКолонка).
  2. При выводе ячейки данных используем ТабДок.Присоединить(Макет.ПолучитьОбласть("СекцияСтрока|СекцияКолонка")).

Это особенно удобно, если у вас разные типы оформления для разных колонок или строк (например, выделение выходных дней цветом).

Оптимизация и работа с данными

Проанализируем ситуацию, когда данных очень много. Метод Присоединить() может работать медленнее, чем Вывести(), если количество колонок исчисляется сотнями. В таких случаях можно рассмотреть альтернативный вариант:

Использование соответствий (Map):

Выясним, как ускорить процесс без вложенных выборок. Мы можем один раз выгрузить результат запроса в ТаблицуЗначений. Затем создать Соответствие, где ключом будет уникальная комбинация (например, Номенклатура + Дата), а значением — Количество. При обходе макета мы просто будем обращаться к этому соответствию. Это избавляет от необходимости использовать параметр "ВСЕ" в запросе и делает код более прозрачным.

Заключение и рекомендации

Резюмируем основные правила построения кросс-таблиц вручную:

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

← На главную