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

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

В практике разработки на платформе 1С:Предприятие часто возникает задача агрегации данных: например, когда для одной номенклатуры в базе данных заведено несколько проектов, и нам нужно вывести их названия в одной ячейке через запятую. Если в классическом SQL для этого существуют встроенные функции вроде STRING_AGG или GROUP_CONCAT, то язык запросов 1С, к сожалению, не поддерживает такую операцию напрямую.

В этой статье мы подробно разберем, как обойти это ограничение, используя возможности системы компоновки данных (СКД), хитрости языка запросов и программную постобработку. Мы проанализируем различные подходы, от самых простых до наиболее производительных.

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

Это наиболее правильный и "цивилизованный" метод решения задачи в современной среде 1С. Платформа предоставляет специальные агрегатные функции в языке выражений СКД, которые выполняются уже на этапе компоновки результата, после получения данных из СУБД.

Рассмотрим по шагам, как настроить сбор строк в СКД:

  1. Добавим в запрос необходимые поля (например, Номенклатура и Проект).
  2. Перейдем на закладку "Вычисляемые поля" или сразу в "Ресурсы".
  3. Для поля Проект в колонке "Выражение" пропишем использование функции СоединитьСтроки.

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


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

Разберем, что здесь происходит: ВычислитьВыражениеСГруппировкойМассив собирает все значения поля Проект в рамках текущей группировки Номенклатура в массив. Затем функция СоединитьСтроки берет этот массив и объединяет его элементы в одну строку, используя разделитель ", ".

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


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

Решение №2: Вызов функций общего модуля из СКД

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

Алгоритм действий следующий:

  1. Создадим общий модуль (например, РаботаСоСтроками) и установим флаги "Сервер" и "Вызов сервера".
  2. Напишем функцию, принимающую массив значений:

Функция СклеитьПроекты(МассивПроектов) Экспорт
    Если МассивПроектов = Неопределено Тогда
        Возврат "";
    КонецЕсли;
    
    // Удаляем дубли и пустые значения
    Результат = "";
    Для Каждого Стр Из МассивПроектов Цикл
        Если ЗначениеЗаполнено(Стр) И Найти(Результат, Стр) = 0 Тогда
            Результат = Результат + ?(Результат = "", "", ", ") + Стр;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции
  1. В СКД на закладке "Ресурсы" для поля Проект вызовем нашу функцию:

РаботаСоСтроками.СклеитьПроекты(ВычислитьВыражениеСГруппировкойМассив("Проект", "Номенклатура"))

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

Решение №3: Трюки в языке запросов (для ограниченного количества строк)

Если использование СКД по каким-то причинам невозможно (например, данные нужны строго внутри программного кода в виде таблицы значений), и мы точно знаем, что количество объединяемых строк невелико (до 5–10), можно прибегнуть к "костыльному", но рабочему методу с использованием ЛЕВОГО СОЕДИНЕНИЯ и конструкции ВЫБОР.

Проанализируем пример, где мы заранее нумеруем строки (или предполагаем наличие уникального признака) и сворачиваем их в одну строку:


ВЫБРАТЬ
    Таблица1.Номенклатура КАК Номенклатура,
    МАКСИМУМ(ВЫБОР КОГДА Таблица2.НомерСтроки = 1 ТОГДА Таблица2.Проект ИНАЧЕ "" КОНЕЦ) КАК Проект1,
    МАКСИМУМ(ВЫБОР КОГДА Таблица2.НомерСтроки = 2 ТОГДА Таблица2.Проект ИНАЧЕ "" КОНЕЦ) КАК Проект2,
    МАКСИМУМ(ВЫБОР КОГДА Таблица2.НомерСтроки = 3 ТОГДА Таблица2.Проект ИНАЧЕ "" КОНЕЦ) КАК Проект3
ПОМЕСТИТЬ втСвернуто
ИЗ
    втОсновныеДанные КАК Таблица1
ЛЕВОЕ СОЕДИНЕНИЕ втПроекты КАК Таблица2 ПО Таблица1.Номенклатура = Таблица2.Номенклатура
СГРУППИРОВАТЬ ПО
    Таблица1.Номенклатура
;

ВЫБРАТЬ
    втСвернуто.Номенклатура,
    втСвернуто.Проект1 + 
    ВЫБОР КОГДА втСвернуто.Проект2 <> "" ТОГДА ", " + втСвернуто.Проект2 ИНАЧЕ "" КОНЕЦ +
    ВЫБОР КОГДА втСвернуто.Проект3 <> "" ТОГДА ", " + втСвернуто.Проект3 ИНАЧЕ "" КОНЕЦ КАК ВсеПроекты
ИЗ
    втСвернуто КАК втСвернуто

Важно: Этот метод крайне не рекомендуется для больших объемов данных, так как он сильно нагружает СУБД и требует заранее известного максимального количества объединяемых элементов.

Решение №4: Программный обход результата запроса с итогами

Если нам нужно вывести данные в печатную форму или специализированный отчет, самый быстрый и надежный способ — это использование предложения ИТОГИ в запросе и последующая программная обработка.

Выясним, как это реализовать:

  1. Пишем запрос с группировкой по родителю и детальными записями.
  2. Используем конструкцию ИТОГИ ПО.

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура,
    |   Проект
    |ИЗ
    |   Справочник.ПроектыНоменклатуры
    |ИТОГИ ПО
    |   Номенклатура";

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

Пока ВыборкаНоменклатура.Следующий() Цикл
    СписокПроектов = "";
    ВыборкаДетальные = ВыборкаНоменклатура.Выбрать();
    
    Пока ВыборкаДетальные.Следующий() Цикл
        СписокПроектов = СписокПроектов + ?(СписокПроектов = "", "", ", ") + ВыборкаДетальные.Проект;
    КонецЦикла;
    
    // Теперь у нас есть переменная СписокПроектов, которую можно выводить в строку
    Сообщить("Номенклатура: " + ВыборкаНоменклатура.Номенклатура + " Проекты: " + СписокПроектов);
КонецЦикла;

Этот подход работает быстрее всех остальных на стороне сервера 1С, так как агрегация строк происходит в памяти сервера приложений, а не в тяжелых запросах к базе данных.

Сравнение методов и нюансы производительности

Подводя итоги, проанализируем, какой метод выбрать в зависимости от ситуации:

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

← На главную