Как в запросе 1С получить соединенное поле типа строка из нескольких записей

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

При работе с данными в 1С программисты часто сталкиваются с задачей, когда необходимо сгруппировать записи по определенным полям, а значения строкового поля — не просто выбрать, а «склеить» в одну длинную строку. Например, если у одного контрагента есть несколько номеров телефонов, хранящихся в разных строках, мы хотим получить одну строку, где номера перечислены через запятую.

Проанализируем ситуацию: стандартный оператор СГРУППИРОВАТЬ ПО в языке запросов 1С поддерживает агрегатные функции, такие как СУММА, МАКСИМУМ или КОЛИЧЕСТВО, но в нем отсутствует встроенная функция для агрегации строк (аналог STRING_AGG в MS SQL или group_concat в MySQL). Выясним причину этого ограничения и разберем все доступные способы решения этой задачи.

Почему в языке запросов 1С нет функции агрегации строк?

Язык запросов 1С спроектирован как универсальный механизм, который должен одинаково работать на различных системах управления базами данных (СУБД): MS SQL Server, PostgreSQL, IBM DB2 и Oracle. Исторически сложилось так, что функции объединения строк в этих системах называются по-разному и имеют разный синтаксис (например, требования к сортировке внутри строки). Платформа 1С придерживается концепции максимальной совместимости, поэтому сложные функции агрегации строк вынесены за пределы стандартного языка запросов.

Рассмотрим подробнее три основных способа реализации этой задачи: использование Системы компоновки данных (СКД), программную постобработку результата и «хитрости» в самих запросах.

Способ 1. Использование Системы компоновки данных (СКД)

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

Разберем по шагам, как настроить объединение строк в схеме компоновки:

  1. Откроем вкладку Ресурсы в схеме компоновки данных.
  2. Выберем поле, строки которого нужно соединить (например, Поле25).
  3. В колонке Выражение напишем специальную функцию:

СоединитьСтроки(ВычислитьВыражениеСГруппировкойМассив("Поле25"), ", ")

Проанализируем, как работает это выражение. Функция ВычислитьВыражениеСГруппировкойМассив собирает все значения Поле25, попадающие в текущую группировку, в массив. Затем функция СоединитьСтроки берет этот массив и превращает его в одну строку, разделяя элементы указанным разделителем (в нашем примере — запятой с пробелом).

Если нам нужно, чтобы строки внутри результата шли в определенном порядке, мы можем добавить сортировку прямо в выражение:


СоединитьСтроки(ВычислитьВыражениеСГруппировкойМассив("Поле25", "Поле25 Возр"), "; ")

Способ 2. Программная постобработка через Соответствие или Таблицу значений

Если данные нужны не для отчета, а для использования в коде (например, для заполнения документа), мы можем выполнить обычный запрос без группировки строкового поля, а затем «свернуть» результат программно.

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


// Предположим, РезультатЗапроса содержит колонки: КлючГруппировки, ЗначениеСтроки
ТаблицаРезультат = РезультатЗапроса.Выгрузить();
СоответствиеГрупп = Новый Соответствие;

Для Каждого Строка Из ТаблицаРезультат Цикл
    ТекущееЗначение = СоответствиеГрупп.Получить(Строка.КлючГруппировки);
    
    Если ТекущееЗначение = Неопределено Тогда
        СоответствиеГрупп.Вставить(Строка.КлючГруппировки, Строка.ЗначениеСтроки);
    Иначе
        НовоеЗначение = ТекущееЗначение + ", " + Строка.ЗначениеСтроки;
        СоответствиеГрупп.Вставить(Строка.КлючГруппировки, НовоеЗначение);
    КонецЕсли;
КонецЦикла;

Посмотрим на этот процесс: мы проходим по всем строкам один раз. Если ключ (по которому мы группируем) встречается впервые — добавляем его в соответствие. Если ключ уже есть — извлекаем накопленную строку, прибавляем к ней новую и сохраняем обратно. Это классический алгоритм свертки данных вручную.

Способ 3. Соединение фиксированного количества полей в запросе

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

Посмотрим на пример такого запроса:


ВЫБРАТЬ
    Т1.Поле1 КАК Поле1,
    Т1.Поле2 КАК Поле2,
    ЕСТЬNULL(Т1.ПолеСтрока, "") + " " + ЕСТЬNULL(Т2.ПолеСтрока, "") КАК СоединенноеПоле
ИЗ
    ИсходныеДанные КАК Т1
    ЛЕВОЕ СОЕДИНЕНИЕ ИсходныеДанные КАК Т2
        ПО Т1.Поле1 = Т2.Поле1
        И Т1.Поле2 = Т2.Поле2
        И Т1.ПолеСтрока < Т2.ПолеСтрока
ГДЕ
    ...

Важный момент: Обратите внимание на использование функции ЕСТЬNULL. В языке запросов 1С, если прибавить строку к значению NULL, результатом всегда будет NULL. Чтобы не потерять данные, когда второе поле пустое, мы обязательно заменяем NULL на пустую строку "".

Важные рекомендации и нюансы

При выборе метода решения учитывайте следующие особенности:

  1. Производительность: Если записей в выборке тысячи, программная обработка может занять время. Старайтесь максимально фильтровать данные в запросе перед тем, как начинать их объединять в коде.
  2. Ограничение длины строк: В некоторых версиях СУБД существуют ограничения на максимальную длину строки. При агрегации сотен коротких строк в одну очень длинную можно столкнуться с обрезанием данных.
  3. Типы данных: Функция СоединитьСтроки в СКД умеет работать не только со строками, но и с числами или датами, автоматически приводя их к строковому виду. В обычном запросе через + складывать можно только строковые типы данных.
  4. Удаление дублей: При использовании СоединитьСтроки в СКД часто возникает потребность объединять только уникальные значения. Для этого внутри функции ВычислитьВыражениеСГруппировкойМассив можно использовать ключевое слово Distinct (если это поддерживается конкретной версией платформы) или предварительно сгруппировать данные в самом запросе.

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

← На главную