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