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