Как объединить несколько элементов справочника в одну строку при заполнении табличной части

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

В процессе разработки на платформе 1С:Предприятие часто возникает задача вывода данных типа "один ко многим" в плоский список. Типичный пример: у одного основного объекта (например, "Риск") может быть несколько подчиненных объектов (например, "Причины"). Если использовать обычное соединение в запросе, система вернет столько строк, сколько существует причин, дублируя при этом основной объект. Наша цель — сгруппировать все причины и записать их через запятую в одну ячейку табличной части. Рассмотрим, как это сделать правильно и эффективно.

Проблема стандартного соединения в запросе

Когда мы используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ или ЛЕВОЕ СОЕДИНЕНИЕ между владельцем и подчиненным справочником, результат запроса выглядит избыточным. Проанализируем ситуацию: если для одного риска существует три причины, запрос выдаст три записи. При обычном обходе выборки в табличную часть добавятся три разные строки, что не соответствует требованиям интерфейса. Нам же необходимо получить одну строку, где в колонке Риск будет ссылка на объект, а в колонке Причина — текстовый перечень всех связанных элементов.

Решение через конструкцию ИТОГИ ПО

Наиболее элегантный способ решения этой задачи на уровне запроса — использование секции ИТОГИ ПО. Это позволяет структурировать результат запроса в виде иерархического дерева, где на верхнем уровне находятся наши основные объекты (риски), а на подчиненном — детальные записи (причины).

Разберем пример построения такого запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Услуги.Ссылка КАК Риск,
    |   ПричиныРисков.Ссылка КАК Причина
    |ИЗ
    |   Справочник.Услуги КАК Услуги
    |       ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПричиныРисков КАК ПричиныРисков
    |       ПО Услуги.Ссылка = ПричиныРисков.Владелец
    |ГДЕ
    |   Услуги.Ссылка В ИЕРАРХИИ(&Подразделение)
    |   И Услуги.ЭтоГруппа = ЛОЖЬ
    |   И ПричиныРисков.ПометкаУдаления = ЛОЖЬ
    |ИТОГИ ПО
    |   Риск";

Запрос.УстановитьПараметр("Подразделение", Объект.Подразделение);
РезультатЗапроса = Запрос.Выполнить();

Обход выборки по группировкам

После выполнения запроса с итогами нам необходимо правильно обработать результат. Обычный метод Выбрать() здесь не подойдет — нам нужно использовать ОбходРезультатаЗапроса.ПоГруппировкам. Это позволит нам создать внешний цикл для формирования строк табличной части и вложенный цикл для сбора всех причин текущего риска в одну строку.

Рассмотрим алгоритм обработки:

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

Вариант 1: Использование функции СтрСоединить (для платформы 8.3.6 и выше)

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


ВыборкаРисков = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаРисков.Следующий() Цикл
    // Создаем строку в ТЧ только один раз для каждого риска
    НоваяСтрока = Объект.Причины.Добавить();
    НоваяСтрока.Риск = ВыборкаРисков.Риск;
    
    // Собираем причины во вложенном цикле
    МассивПричин = Новый Массив;
    ВыборкаДетальные = ВыборкаРисков.Выбрать();
    
    Пока ВыборкаДетальные.Следующий() Цикл
        // Добавляем наименование в массив
        МассивПричин.Добавить(Строка(ВыборкаДетальные.Причина));
    КонецЦикла;
    
    // Объединяем массив в одну строку через запятую
    НоваяСтрока.Причина = СтрСоединить(МассивПричин, ", ");
КонецЦикла;

Вариант 2: Реализация для старых платформ и режима совместимости

Если при попытке использовать СтрСоединить система выдает ошибку "Функция не определена", значит, используется платформа версии ниже 8.3.6 или включен соответствующий режим совместимости. В этом случае мы реализуем объединение строк вручную с помощью обычного накопления в переменную.

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


ВыборкаРисков = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

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

Оптимизация работы с данными

При реализации подобных механизмов стоит обратить внимание на производительность, особенно если справочники содержат тысячи записей. Рассмотрим несколько советов:

Таким образом, мы выяснили, что задача "запихивания" нескольких элементов в один реквизит решается не на уровне плоской выборки, а путем правильной группировки данных в запросе через ИТОГИ ПО и последующей обработки вложенных коллекций в коде 1С.

← На главную