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