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