Как объединить строки в детальных записях СКД и вывести повторяющиеся значения массивом или строкой?

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

При разработке отчетов на Системе компоновки данных (СКД) в 1С программисты часто сталкиваются с проблемой избыточности данных. Представим ситуацию: в вашем отчете должно выводиться 10 колонок. По 9 колонкам информация абсолютно идентична, но в десятой колонке (например, «Номер акта» или «Сертификат») содержатся разные значения. В результате на уровне базы данных мы получаем несколько строк, которые при выводе отчета дублируют всю основную информацию ради одного различающегося поля.

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

Почему стандартный подход в детальных записях не работает?

Для начала проанализируем причину проблемы. Когда в настройках структуры отчета СКД мы используем элемент Детальные записи, система выводит строки в том виде, в котором они приходят из источника данных (запроса). Если в результате SQL-запроса вернулось 5 строк (так как у одного заказа может быть 5 разных актов), СКД послушно выведет все 5 строк.

Попытка написать в ресурсах выражение вида Массив(Различные НомерАкта) не схлопывает строки сами по себе. Ресурсы рассчитываются только для группировок. На уровне детальной записи (которая группировкой не является) контекст вычисления выражения равен текущей строке. В результате для каждой строки мы получаем массив из одного единственного элемента — значения текущей строки, а дублирование информации по остальным колонкам сохраняется.

Выражение ВычислитьВыражениеСГруппировкойМассив предназначено для совершенно других целей — для так называемого двойного агрегирования. Например, когда нам нужно на уровне номенклатуры рассчитать максимальные продажи, а затем на уровне группы сложить эти максимумы. Свернуть детальные записи в одну строку эта функция не поможет.

Ниже мы подробно разберем три рабочих сценария решения этой задачи.

Решение №1. Использование связи двух наборов данных (без кода)

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

Рассмотрим этот алгоритм по шагам:

  1. Создаем НаборДанных1 (основной): Напишем запрос, который выбирает только уникальные записи по основным 9 колонкам. Для этого используем ключевое слово РАЗЛИЧНЫЕ или сгруппируем данные в самом запросе. Колонка «Номер акта» в этом запросе присутствовать не должна. Основным связующим полем будет, например, Заказ.
  2. Создаем НаборДанных2 (вспомогательный): Этот запрос будет выбирать только ключевое поле связи (Заказ) и поле, которое необходимо собрать в массив (НомерАкта).
  3. Настраиваем связь наборов данных: Перейдем на вкладку «Связи наборов данных» и добавим новую строку:
    • Источник связи: НаборДанных1
    • Приемник связи: НаборДанных2
    • Условие связи: Заказ = Заказ
  4. Создаем ресурс: Перейдем на вкладку «Ресурсы». Добавим поле НомерАкта в список ресурсов. В качестве выражения укажем:

    СоединитьСтроки(Массив(Различные НомерАкта), "; ")

  5. Настраиваем вывод: В структуре отчета создаем обычные Детальные записи. Выводим поля из первого набора данных и ресурсное поле НомерАкта.

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

Решение №2. Имитация детальных записей через группировку

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

Разберем данный подход:

  1. В схеме компоновки на вкладке «Ресурсы» определим поле НомерАкта как ресурс с выражением:

    СоединитьСтроки(Массив(Различные НомерАкта), "; ")

  2. Перейдем в настройки структуры отчета на вкладку «Настройки». Вместо стандартного элемента «Детальные записи» добавим Группировку.
  3. В поля группировки добавим все 9 полей, которые у нас уникальны (например: Организация, Контрагент, Заказ, Договор и т.д.).
  4. В выбранные поля этой группировки добавим наши 9 полей и ресурс НомерАкта.
  5. Чтобы отчет не выглядел как классическое дерево группировок с отступами и иерархией, настроим его внешний вид. Выделим нашу группировку, перейдем в ее системные свойства («Другие настройки») и установим параметр Расположение группировок в значение Нет. Также рекомендуется выключить общие итоги по вертикали и горизонтали, если они не требуются.

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

Решение №3. Использование функции общего модуля

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

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

Пример кода функции общего модуля (назовем его УправлениеОтчетами):


Функция СклеитьЗначенияПоля(ТаблицаДанных, КлючевоеПоле, ЗначениеКлюча, ИмяПоляАгрегации) Экспорт

    // Фильтруем таблицу по ключевому полю
    ПараметрыОтбора = Новый Структура(КлючевоеПоле, ЗначениеКлюча);
    СтрокиТаблицы = ТаблицаДанных.НайтиСтроки(ПараметрыОтбора);
    
    МассивЗначений = Новый Массив;
    Для Каждого СтрокаДанных Из СтрокиТаблицы Цикл
        Если ЗначениеЗаполнено(СтрокаДанных[ИмяПоляАгрегации]) Тогда
            // Исключаем дублирование значений в результирующем массиве
            Если МассивЗначений.Найти(СтрокаДанных[ИмяПоляАгрегации]) = Неопределено Тогда
                МассивЗначений.Добавить(СтрокаДанных[ИмяПоляАгрегации]);
            EndIf;
        EndIf;
    КонецЦикла;
    
    Возврат СтрСоединить(МассивЗначений, "; ");

КонецФункции

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

УправлениеОтчетами.СклеитьЗначенияПоля(НаборДанных, "Заказ", Заказ, "НомерАкта")

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

Продвинутые возможности агрегации в СКД

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

Например, если нам нужно вывести не просто список номеров актов, а связать каждый номер с его датой, мы можем использовать конструкцию:

СоединитьСтроки(ТаблицаЗначений(НомерАкта, ДатаАкта), "; ", " от ")

При использовании такого выражения на выходе мы получим отформатированную строку следующего вида:

«Акт №123 от 10.05.2026; Акт №124 от 12.05.2026»

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

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

← На главную