При построении аналитических отчетов и обработок часто возникает задача вывести линейный список данных в виде матрицы или шахматки (кросс-таблицы). На практике это означает, что в строках матрицы должны располагаться ключевые объекты (например, клиенты или сотрудники), в колонках — динамический перечень показателей, а в ячейках на пересечении — их значения.
Рассмотрим основные способы решения этой задачи в платформе 1С, выясним технические ограничения системы компоновки данных (СКД) и разберем примеры программного формирования элементов формы.
Система компоновки данных позволяет быстро выгружать результаты отчетов в объект ТаблицаЗначений. Для этого используется программный вывод с помощью специализированных процессоров компоновки:
Макет = КомпоновщикМакета.Выполнить(Схема, КомпоновщикНастроек0.ПолучитьНастройки(),,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки.Инициализировать(Макет);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
Таблица = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(Таблица);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Важное ограничение: данный подход корректно работает только для плоских таблиц с группировками по строкам. Если в настройках СКД сформирована структура типа «Таблица» (кросс-таблица с группировками как по строкам, так и по колонкам), объект ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений не сможет развернуть колонки в динамическую коллекцию и выведет плоский список либо вызвет ошибку выполнения.
Если данные необходимо выводить в объект ТаблицаЗначений на управляемой форме с возможностью редактирования и расчетов, потребуется программное добавление колонок как в структуру реквизита формы, так и в графические элементы интерфейса.
Попытка вызвать метод Элементы.Добавить() без предварительного изменения структуры реквизитов формы приведет к ошибке: Недопустимое значение параметра (параметр номер '1').
Проанализируем правильный двухуровневый алгоритм создания колонок на сервере:
ИзменитьРеквизиты() создаются новые поля для объекта формы.Элементы.Добавить() с указанием вида элемента ВидПоляФормы.ПолеВвода и пути к данным.Разберем пример кода добавления динамических колонок на управляемой форме:
// Шаг 1. Формируем массив новых реквизитов формы
МассивДобавляемыхРеквизитов = Новый Массив;
Для Каждого СтрИз СправочникПоказателей Цикл
// Имя реквизита должно удовлетворять правилам идентификаторов BSL
ИмяКолонки = "Показатель_" + СтрИз.Код;
ТипыКолонки = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы(ИмяКолонки, ТипыКолонки, "ТЗ", СтрИз.Наименование));
КонецЦикла;
// Регистрируем новые реквизиты в контексте формы
ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);
// Шаг 2. Создаем элементы интерфейса
Для Каждого СтрИз СправочникПоказателей Цикл
ИмяКолонки = "Показатель_" + СтрИз.Код;
НоваяКолонка = Элементы.Добавить(ИмяКолонки, Тип("ПолеФормы"), Элементы.ТЗ);
НоваяКолонка.Заголовок = СтрИз.Наименование;
НоваяКолонка.ПутьКДанным = "ТЗ." + ИмяКолонки;
НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
НоваяКолонка.РежимРедактирования = РежимРедактированияКолонки.ВходПриВводе;
КонецЦикла;
При повторном переформировании таблицы не забудьте удалить ранее созданные элементы через Элементы.Удалить() и очистить реквизиты через второй параметр метода ИзменитьРеквизиты().
Если основной задачей является отображение кросс-таблицы с автоматическими итогами без необходимости сложного программного редактирования каждой ячейки, удобным решением выступает объект СводнаяТаблица, размещенный в ПолеТабличногоДокумента.
Для этого в запросе формируются итоги по группировкам строк и колонок, после чего результат передается в источник данных сводной таблицы:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СостояниеРаботников.Сотрудник КАК Сотрудник,
| СостояниеРаботников.Состояние КАК Состояние,
| СостояниеРаботников.Регистратор КАК Регистратор
|ИЗ
| РегистрСведений.СостояниеРаботниковОрганизаций КАК СостояниеРаботников
|ГДЕ
| СостояниеРаботников.Период МЕЖДУ &Д1 И &Д2
|ИТОГИ
| КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Регистратор)
|ПО
| Сотрудник,
| Состояние";
Запрос.УстановитьПараметр("Д1", НачалоДня(Дата1));
Запрос.УстановитьПараметр("Д2", КонецДня(Дата2));
Результат = Запрос.Выполнить();
// ПолеТабДок - элемент формы с типом ПолеТабличногоДокумента
СводТаб = ЭлементыФормы.ПолеТабДок.ВстроенныеТаблицы.Добавить(Тип("СводнаяТаблица"));
СводТаб.ИсточникДанных = Результат;
Данный подход позволяет встроенными средствами платформы получить полноценную интерактивную шахматку с возможностью сворачивания и группировки данных пользователем.
Если перечень показателей известeн заранее или его можно динамически сформировать перед выполнением запроса, разворот из строк в колонки выгодно выполнять прямо в тексте запроса через условное агрегирование:
ВЫБРАТЬ
Продажи.Клиент КАК Клиент,
СУММА(ВЫБОР КОГДА Продажи.Показатель = &Показатель1 ТОГДА Продажи.Значение ИНАЧЕ 0 КОНЕЦ) КАК Выручка,
СУММА(ВЫБОР КОГДА Продажи.Показатель = &Показатель2 ТОГДА Продажи.Значение ИНАЧЕ 0 КОНЕЦ) КАК Количество
ИЗ
РегистрНакопления.Продажи КАК Продажи
СГРУППИРОВАТЬ ПО
Продажи.Клиент
Результат такого запроса выгружается в обычную плоскую ТаблицаЗначений, которую не требуется дополнительно обрабатывать алгоритмами обхода ячеек.