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