Как построить кросс-отчет с динамическим количеством колонок без СКД

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

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

Рассмотрим, почему стандартный язык запросов 1С не формирует готовую шахматную таблицу «из коробки», а также разберем по шагам практические способы реализации такого отчета: от ручного вывода выборки до использования встроенных инструментов платформы.

Ограничения языка запросов 1С при формировании колонок

В языке запросов 1С отсутствует прямая поддержка оператора PIVOT, применяемого в классическом SQL для автоматического разворота строк в столбцы. Запрос всегда возвращает плоскую таблицу данных фиксированной структуры, где поля определены в секции ВЫБРАТЬ, либо иерархический результат с итогами по строкам.

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


ВЫБРАТЬ
	Обороты.Участок КАК Участок,
	Обороты.Клиент КАК Клиент,
	Обороты.КоличествоОборот КАК Количество
ИЗ
	РегистрНакопления.ПродажиПоУчасткам.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Обороты
ИТОГИ
	СУММА(Количество)
ПО
	Участок,
	Клиент

Обращение к виртуальной таблице оборотов использует встроенные таблицы итогов регистра, что значительно повышает скорость работы по сравнению с физической таблицей регистра накопления.

Решение 1. Программный вывод кросс-таблицы через обход группировок запроса

Если поставлена задача реализовать алгоритм вручную без СКД, нам потребуется сформировать макет табличного документа с пересекающимися областями и правильно обойти результат запроса.

Макет разбивается на вертикальные секции (например, КолонкаУчасток, КолонкаКлиент, КолонкаИтог) и горизонтальные секции (Шапка, СтрокаДанных, Подвал). Вывод ячеек на пересечении осуществляется сочетанием методов ТабличныйДокумент.Вывести() (для начала строки) и ТабличныйДокумент.Присоединить() (для добавления колонок в текущую строку).

Разберем пример программного вывода данных, где для горизонтального разворота используется обход группировки с ключевым словом "Все":


ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("Макет");

ОбластьШапкаУчасток = Макет.ПолучитьОбласть("Шапка|КолонкаУчасток");
ОбластьШапкаКлиент  = Макет.ПолучитьОбласть("Шапка|КолонкаКлиент");
ОбластьСтрокаУчасток = Макет.ПолучитьОбласть("СтрокаДанных|КолонкаУчасток");
ОбластьСтрокаКлиент  = Макет.ПолучитьОбласть("СтрокаДанных|КолонкаКлиент");
ОбластьПодвалУчасток = Макет.ПолучитьОбласть("Подвал|КолонкаУчасток");
ОбластьПодвалКлиент  = Макет.ПолучитьОбласть("Подвал|КолонкаКлиент");

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

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

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

// 3. Вывод подвала с общими итогами
ТабДок.Вывести(ОбластьПодвалУчасток);
ВыборкаКлиентыШапка.Сбросить();
Пока ВыборкаКлиентыШапка.Следующий() Цикл
	ОбластьПодвалКлиент.Параметры.Количество = ВыборкаКлиентыШапка.Количество;
	ТабДок.Присоединить(ОбластьПодвалКлиент);
КонецЦикла;

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

Решение 2. Быстрый шахматный отчет через «ПостроительОтчета»

Если стоит цель минимизировать объем программного кода и не рисовать макет вручную, отличной альтернативой выступает объект ПостроительОтчета. Он умеет самостоятельно транспонировать измерения в колонки таблицы.

Рассмотрим, как настроить вывод шахматной таблицы буквально в несколько строк кода:


Построитель = Новый ПостроительОтчета;
Построитель.Текст = 
	"ВЫБРАТЬ
	|	Обороты.Участок КАК Участок,
	|	Обороты.Клиент КАК Клиент,
	|	Обороты.КоличествоОборот КАК Количество
	|ИЗ
	|	РегистрНакопления.ПродажиПоУчасткам.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Обороты";

Построитель.Параметры.Вставить("НачалоПериода", ПериодНачала);
Построитель.Параметры.Вставить("КонецПериода", ПериодОкончания);

// Настраиваем измерения строк, колонок и ресурсы
Построитель.ИзмеренияСтроки.Добавить("Участок");
Построитель.ИзмеренияКолонки.Добавить("Клиент");
Построитель.ВыбранныеПоля.Добавить("Количество");

// Очищаем макет для автогенерации структуры
Построитель.Макет = Неопределено;

// Формируем готовый документ
ТабличныйДокумент = Новый ТабличныйДокумент;
Построитель.Вывести(ТабличныйДокумент);
ТабличныйДокумент.Показать();

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

Решение 3. Использование Системы компоновки данных (СКД)

Наиболее современным и стандартным решением для задач подобного рода является Система компоновки данных. Создание матрицы в СКД выполняется без единой строчки программного кода:

  1. В наборе данных «Запрос» указывается обращение к виртуальной таблице оборотов регистра.
  2. На вкладке Ресурсы поле Количество отмечается ресурсом с выражением Сумма(Количество).
  3. На вкладке Настройки в структуру отчета добавляется элемент Таблица.
  4. В раздел Строки таблицы переносится поле Участок, а в раздел Колонки — поле Клиент.

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

← На главную