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

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

При разработке отчетов или обработок в 1С часто возникает задача, когда одна сущность (например, Событие) связана с несколькими подчиненными элементами (например, Контакт). Стандартный Запрос при соединении таблиц вернет столько строк, сколько контактов привязано к событию. Если же нам нужно получить результат вида: «Событие, [Контакт1, Контакт2]», возникают сложности, так как стандартный язык запросов 1С не поддерживает агрегатные функции типа STRING_AGG или GROUP_CONCAT напрямую.

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

Решение методом постобработки таблицы значений

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

Разберем алгоритм по шагам:

  1. Выполняем запрос и выгружаем его в ТаблицаДанных.
  2. Добавляем индекс к таблице, чтобы ускорить поиск по полям, которые не должны дублироваться (например, Событие и Содержание).
  3. Создаем копию структуры таблицы для хранения итогового результата.
  4. Итерируем данные и объединяем контакты в одну строку.

Посмотрим на пример реализации кода:


ТаблицаДанных = Запрос.Выполнить().Выгрузить();
ТаблицаДанных.Индексы.Добавить("Событие, СодержаниеСобытия");

УникальныеЗаписи = ТаблицаДанных.Скопировать(, "Событие, СодержаниеСобытия");
УникальныеЗаписи.Свернуть("Событие, СодержаниеСобытия");

РезультатТаблица = ТаблицаДанных.СкопироватьКолонки();
РезультатТаблица.Колонки.Добавить("СписокКонтактов");

Для Каждого УникальнаяЗапись Из УникальныеЗаписи Цикл
    НСтр = РезультатТаблица.Добавить();
    ЗаполнитьЗначенияСвойств(НСтр, УникальнаяЗапись);
    
    Отбор = Новый Структура("Событие, СодержаниеСобытия", УникальнаяЗапись.Событие, УникальнаяЗапись.СодержаниеСобытия);
    МассивКонтактов = ТаблицаДанных.НайтиСтроки(Отбор);
    
    Список = "";
    Для Сч = 0 По МассивКонтактов.Количество() - 1 Цикл
        Список = Список + ?(Сч = 0, "", ", ") + МассивКонтактов[Сч].Контакт;
    КонецЦикла;
    НСтр.СписокКонтактов = Список;
КонецЦикла;

Важно отметить: использование метода НайтиСтроки для индексированной таблицы работает быстро, что позволяет эффективно обрабатывать небольшие и средние объемы данных.

Решение методом двух запросов (Пакетная выборка)

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

  1. Первым запросом выбираем только список последних 5 событий (без контактов). Выгружаем их в ТЗ.
  2. Передаем полученный список событий во второй запрос как параметр (используем ВТ — временную таблицу).
  3. Во втором запросе выбираем контакты только для этих 5 событий.
  4. Объединяем данные в коде, используя структуру или временное хранилище.

Такой подход делает логику более прозрачной. Мы сначала четко определяем, какие именно события нас интересуют, и лишь затем добираем по ним детализированную информацию, не создавая избыточных соединений.

Рекомендации по оптимизации

При работе с конкатенацией строк в 1С следуйте этим правилам:

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

← На главную