Как вывести содержимое группировки по горизонтали в СКД

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

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

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

Способ 1. Использование механизма нумерации строк в запросе (Тета-соединение)

Это самый гибкий и профессиональный метод. Его суть заключается в том, чтобы программно присвоить каждой строке внутри одной группы порядковый номер (1, 2, 3 и так далее). Этот номер впоследствии будет использоваться СКД как индекс колонки.

Разберем по шагам логику построения запроса:

  1. Выберем исходные данные во временную таблицу. Допустим, у нас есть поле Объект и поле Значение.
  2. Соединим эту таблицу саму с собой по условию равенства ключевого поля (Объект) и условию «больше или равно» для целевого значения (Значение).
  3. Сгруппируем результат и посчитаем количество записей. Это количество и будет номером нашей будущей колонки.

Проанализируем пример кода такого запроса:


ВЫБРАТЬ
    Аналоги.Номенклатура КАК Номенклатура,
    Аналоги.Аналог КАК Аналог
ПОМЕСТИТЬ ВТ_Данные
ИЗ
    Справочник.Аналоги КАК Аналоги;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Т1.Номенклатура КАК Номенклатура,
    Т1.Аналог КАК Аналог,
    КОЛИЧЕСТВО(Т2.Аналог) КАК НомерКолонки
ИЗ
    ВТ_Данные КАК Т1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2
        ПО Т1.Номенклатура = Т2.Номенклатура
            И Т1.Аналог >= Т2.Аналог
ГРУППИРОВАТЬ ПО
    Т1.Номенклатура,
    Т1.Аналог

После того как запрос подготовлен, в настройках СКД на вкладке «Настройки» нам нужно изменить структуру отчета:

  1. Вместо обычного «Детальные записи» или «Группировка», добавим элемент типа «Таблица».
  2. В «Строки» таблицы добавим поле Номенклатура.
  3. В «Колонки» таблицы добавим наше вычисленное поле НомерКолонки.
  4. В «Выбранные поля» для всей таблицы (или для пересечения) добавим поле Аналог.

Теперь СКД выведет аналоги в ряд. Чтобы отчет выглядел аккуратно и не содержал заголовков «1», «2», «3» над колонками, в настройках группировки НомерКолонки установим параметр «Расположение группировок» в значение «Нет».

Способ 2. Агрегация в одну ячейку через функцию СоединитьСтроки

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

Посмотрим, как это настроить в конфигураторе:

  1. Перейдем на вкладку «Ресурсы» в схеме компоновки данных.
  2. Добавим поле Аналог в список ресурсов.
  3. В колонке «Выражение» напишем: СоединитьСтроки(Аналог, ", ").
  4. В колонке «Рассчитывать по...» укажем нашу основную группировку (например, Номенклатура).

Этот метод значительно экономит ресурсы сервера, так как не требует сложных соединений в запросе. На выходе мы получим одну колонку, в которой все аналоги будут перечислены строкой: «Аналог 1, Аналог 2, Аналог 3».

Способ 3. Вычисляемые поля и функции массива (для платформы 8.3.15 и выше)

В современных версиях платформы 1С реализованы мощные функции языка выражений СКД, такие как ВычислитьВыражениеСГруппировкойМассив. Мы можем собрать все значения в массив прямо в настройках компоновки, не меняя основной запрос.

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

Особенности оформления и скрытие пустых областей

При использовании табличного вывода (Способ 1) часто возникает проблема избыточного оформления. Выясним, как сделать отчет «чистым»:

  1. Условное оформление: Чтобы убрать границы или лишний текст в пустых ячейках, добавим правило условного оформления. Условие: Поле «Аналог» Не заполнено. Оформление: Минимальная ширина = 0 или Текст = "".
  2. Макеты: Если стандартный вид таблицы СКД вас не устраивает, можно создать собственный Макет группировки или Макет поля. Это позволит задать жесткую ширину ячеек для аналогов, чтобы отчет не растягивался на несколько экранов.
  3. Ограничение количества: Если у одной позиции может быть 100 аналогов, отчет станет нечитаемым. Чтобы избежать этого, в запросе после вычисления НомерКолонки можно добавить условие: ГДЕ НомерКолонки <= 10. Таким образом, мы выведем только первые 10 позиций, что обычно достаточно для бизнес-задач.

Программная подготовка данных (Внешний набор данных)

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


// Пример подготовки таблицы значений в коде
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура");
ТЗ.Колонки.Добавить("Аналог");
ТЗ.Колонки.Добавить("НомерКолонки");

// При обходе выборки или результата запроса в цикле:
Счетчик = 0;
ТекущаяНоменклатура = Неопределено;

Для Каждого Строка Из ДанныеБД Цикл
    Если Строка.Номенклатура <> ТекущаяНоменклатура Тогда
        Счетчик = 1;
        ТекущаяНоменклатура = Строка.Номенклатура;
    Иначе
        Счетчик = Счетчик + 1;
    КонецЕсли;
    
    НоваяСтрока = ТЗ.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
    НоваяСтрока.НомерКолонки = Счетчик;
КонецЦикла;

Затем эта таблица передается в СКД как Внешний набор данных. Это гарантирует максимальную производительность, так как нумерация происходит за один проход по коллекции данных (линейная сложность).

Подводя итог, выбор метода зависит от ваших приоритетов: если нужна быстрота разработки — используйте СоединитьСтроки. Если требуется полноценная таблица с отдельными ячейками — используйте нумерацию через СОЕДИНЕНИЕ в запросе или программную подготовку данных.

← На главную