Разработка и Конфигурация · 10 мин
Как в запросе 1С объединить строки в одну
Как объединить строки в одну в запросе 1С: группировка с СОЕДИНИТЬ, функция СоединитьСтроки, обход выборки. Примеры кода, ограничения и типичные ошибки.
Задача объединить несколько строк результата запроса в одну строку возникает в 1С регулярно: нужно собрать список товаров документа в одно поле, вывести все телефоны контрагента через запятую, сформировать строку для печатной формы или CSV-выгрузки. Важно сразу понимать: в языке запросов 1С нет прямого аналога функции GROUP_CONCAT из MySQL или STRING_AGG из MS SQL, поэтому задача решается обходными путями.
Основных подхода три: группировка в запросе с последующей склейкой в коде, использование функций встроенного языка (СтрСоединить, СоединитьСтроки) после выполнения запроса и приёмы с пакетными запросами и временными таблицами. Выбор зависит от того, где нужен результат — в поле запроса, в отчёте СКД или в обычном коде.
Ниже разобраны рабочие варианты с примерами кода, ограничения каждого способа и типичные ошибки, из-за которых склейка получается пустой, обрезанной или с неправильным порядком элементов.
Почему в запросе 1С нельзя просто «склеить» строки группы
Язык запросов 1С — декларативный: он описывает, какие данные выбрать и как их сгруппировать, но не умеет выполнять итеративную обработку внутри группы. Агрегатные функции ограничены стандартным набором: СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ, СРЕДНЕЕ. Функции «собрать все значения поля в строку» среди них нет.
Оператор «+» в запросе складывает только значения внутри одной строки выборки, а не между строками. Поэтому конструкция вида «Ссылка.Товары.Номенклатура + ", "» на уровне группировки не сработает — запрос либо вернёт ошибку, либо выдаст строки по отдельности.
Вывод: полноценная склейка делается в два этапа — запрос готовит сгруппированные или упорядоченные данные, а объединение выполняет код на встроенном языке. Исключение — отдельные приёмы в СКД, о которых ниже.
Способ 1. Группировка в запросе и склейка обходом выборки
Самый универсальный и надёжный вариант. В запросе выбираются детальные строки с сортировкой по ключу группы, затем в коде строки обходятся и значения накапливаются в массив или строку. Когда ключ меняется — накопленное склеивается и сохраняется.
Пример: нужно для каждого документа получить строку со списком номенклатуры через запятую.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Документ,
| Товары.Номенклатура.Наименование КАК Наименование
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|
|УПОРЯДОЧИТЬ ПО
| Документ";
Выборка = Запрос.Выполнить().Выбрать();
Результат = Новый Соответствие;
ТекущийДокумент = Неопределено;
Части = Новый Массив;
Пока Выборка.Следующий() Цикл
Если ТекущийДокумент <> Выборка.Документ Тогда
Если Части.Количество() > 0 Тогда
Результат.Вставить(ТекущийДокумент, СтрСоединить(Части, ", "));
КонецЕсли;
ТекущийДокумент = Выборка.Документ;
Части = Новый Массив;
КонецЕсли;
Части.Добавить(Выборка.Наименование);
КонецЦикла;
Если Части.Количество() > 0 Тогда
Результат.Вставить(ТекущийДокумент, СтрСоединить(Части, ", "));
КонецЕсли;
Обратите внимание на обязательную обработку последней группы после цикла — это самая частая причина «потери» одного документа в результате. Также важна сортировка по ключу: без УПОРЯДОЧИТЬ ПО Документ строки одной группы могут идти вразнобой, и склейка развалится.
- 1Составьте запрос с детальными строками и добавьте сортировку по ключу группы
- 2Инициализируйте переменные: текущий ключ и массив частей строки
- 3В цикле сравнивайте ключ с предыдущим; при смене ключа склейте массив через СтрСоединить и сохраните результат
- 4После цикла обработайте последнюю накопленную группу
- 5Проверьте результат на документе с одной строкой и на документе без строк
Способ 2. Группировка в запросе, склейка через Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам)
Если в запросе уже есть итоги (Группировка или ИТОГИ ПО), можно обойти результат по группировкам: верхний уровень даст ключ, вложенная выборка — детальные строки. Так код становится чище, а логика группировки переносится в запрос.
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Документ,
| Товары.Номенклатура.Наименование КАК Наименование
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ИТОГИ ПО
| Документ";
ВыборкаДокументы = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаДокументы.Следующий() Цикл
Части = Новый Массив;
Детали = ВыборкаДокументы.Выбрать();
Пока Детали.Следующий() Цикл
Части.Добавить(Детали.Наименование);
КонецЦикла;
СтрокаТоваров = СтрСоединить(Части, ", ");
КонецЦикла;
Этот вариант удобнее, когда помимо склеенной строки нужны ещё и итоговые числа по группе (сумма, количество) — они доступны на верхнем уровне выборки без дополнительного запроса.
Способ 3. Склейка в СКД и консоли отчётов
В системе компоновки данных объединить строки группы в одну можно через собственные функции в общем модуле. В вычисляемом поле или ресурсе вызывается функция, которая принимает ключ группы и возвращает склеенную строку. Функция должна быть экспортной и размещаться в общем модуле с флагом «Сервер».
// В общем модуле
Функция СклеитьСтроки(МассивЗначений) Экспорт
Возврат СтрСоединить(МассивЗначений, ", ");
КонецФункции
Другой путь в СКД — вычисляемое поле с выражением на языке выражений компоновки, но его возможности ограничены: полноценной агрегатной склейки строк там нет, поэтому на практике чаще формируют отчёт с детальными строками, а объединение делают при программной обработке результата компоновки.
Способ 4. Функции СтрСоединить и СоединитьСтроки — в чём разница
Для самой склейки в коде используются две функции. СтрСоединить — современная функция, принимает массив строк и разделитель, работает быстро и предсказуемо. СоединитьСтроки — устаревший вариант из ранних версий платформы, в современных конфигурациях лучше применять СтрСоединить.
Если массив содержит не строки, а числа или ссылки, сначала преобразуйте их функцией Строка() или сформируйте нужное представление — иначе получите системное представление значения, которое не всегда читаемо.
Для больших объёмов не склеивайте строку операцией «Строка = Строка + Кусок» в цикле: каждая операция создаёт новую строку в памяти, и на тысячах элементов это заметно тормозит. Накапливайте части в массиве и один раз вызывайте СтрСоединить.
Сравнение способов склейки
Универсально, работает везде; требует сортировки по ключу и аккуратной обработки последней группы
Чище код, доступны итоги группы; чуть больше памяти на иерархический результат
Результат сразу в отчёте; нужен общий серверный модуль и аккуратность с производительностью
Ограничения и подводные камни
Длина результирующей строки не ограничена жёстко, но если склеенное значение будет выводиться в поле табличного документа или СКД, очень длинные строки портят вёрстку. Разумно ограничивать количество элементов или обрезать строку с добавлением многоточия.
Дубли в склейке — частая проблема. Если в табличной части встречается одна и та же номенклатура несколько раз, она попадёт в строку несколько раз. Решение — перед добавлением проверять Части.Найти(Значение) = Неопределено либо собирать уникальные значения через Соответствие.
Порядок элементов в склеенной строке определяется сортировкой запроса. Если нужен порядок по номеру строки табличной части — добавьте НомерСтроки в выборку и в УПОРЯДОЧИТЬ ПО после ключа группы.
Как проверить результат
Строка содержит одно значение без разделителей
Лишняя запятая в начале или конце
Все значения присутствуют, порядок соответствует табличной части
Пропущены значения или нарушен порядок
Присутствует в результате
Отсутствует — не обработана последняя группа
Отсутствует в результате или пустая строка по логике задачи
Ошибка обращения к пустой выборке
FAQ
Можно ли объединить строки прямо в тексте запроса без кода?
Нет, в языке запросов 1С нет агрегатной функции склейки строк. Максимум, что доступно в запросе, — сложение полей внутри одной строки выборки. Для объединения значений из разных строк группы всегда нужна обработка результата в коде или в СКД.
Чем заменить GROUP_CONCAT из MySQL в 1С?
Шаблон замены: запрос с детальными строками и сортировкой по ключу группы, затем обход выборки с накоплением значений в массив и склейка через СтрСоединить при смене ключа. Либо обход результата по группировкам с ИТОГИ ПО.
Как склеить строки с разделителем-переносом строки?
Передайте в СтрСоединить разделитель Символы.ПС, например: СтрСоединить(Части, Символы.ПС). В табличном документе ячейка с такой строкой отобразит переносы, если включён режим переноса текста.
Как убрать дубликаты из склеенной строки?
Перед добавлением в массив проверяйте наличие значения: Если Части.Найти(Значение) = Неопределено Тогда Части.Добавить(Значение). На больших объёмах быстрее использовать Соответствие как множество уникальных значений, а затем выгрузить ключи.
Почему склейка работает медленно на больших документах?
Чаще всего причина в конкатенации строк операцией «+» внутри цикла — каждая итерация создаёт новую строку в памяти. Замените накоплением в массив и одним вызовом СтрСоединить. Также проверьте, что запрос не выбирает лишние поля и не дублирует строки из-за лишних соединений.
Можно ли склеить строки в динамическом списке?
Напрямую нет: динамический список отображает результат запроса построчно. Обходной путь — добавить в запрос вычисляемое поле через соединение с заранее подготовленной таблицей склеенных значений, но на практике проще выводить такую колонку в отчёте, а не в динамическом списке.
Что важно запомнить
Прямой склейки строк группы в запросе 1С нет. Рабочая схема: запрос с сортировкой по ключу группы → обход выборки → накопление значений в массив → СтрСоединить с нужным разделителем. Не забывайте обработать последнюю группу, убрать дубли и не склеивать строки операцией «+» в цикле.