Как реализовать объединение (свертку) строк в одну в запросе 1С

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

В практике разработчика 1С часто возникает задача, когда при группировке данных необходимо не суммировать числовые показатели, а «склеить» строковые значения. Например, если у нас есть несколько накладных по одной номенклатуре, мы хотим видеть одну строку с названием товара, общую сумму и перечисление номеров всех накладных через запятую. Стандартный язык запросов 1С, в отличие от некоторых диалектов SQL (где есть функции string_agg или LISTAGG), не поддерживает агрегацию строк напрямую. В этой статье мы подробно разберем все доступные способы решения этой задачи: от использования Системы компоновки данных (СКД) до программной обработки результата.

Метод 1. Использование функций СКД «СоединитьСтроки» и «Массив»

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

Рассмотрим по шагам, как это реализовать:

  1. В схеме компоновки данных создадим набор данных — запрос. Напишем обычный запрос, который выбирает номенклатуру, номер накладной и сумму. Группировку в самом тексте запроса делать не обязательно.
  2. Перейдем на закладку «Ресурсы».
  3. В колонке «Поле» выберем наше поле НомерНакладной.
  4. В колонке «Выражение» напишем следующую конструкцию:

СоединитьСтроки(Массив(НомерНакладной), ", ")

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

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

Метод 2. Программная обработка результата запроса в коде

Если по каким-то причинам вы не можете использовать СКД или вам нужно получить готовую таблицу значений для дальнейших манипуляций в коде, следует применить метод обхода выборки. Мы не пытаемся «склеить» строки в самом запросе, а делаем это при чтении данных.

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

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

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


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

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

Этот метод универсален и работает на любой версии платформы 1С:Предприятие 8 — для разработки и отладки таких алгоритмов пригодится инструмент пошаговой отладки программного кода 1С.

Метод 3. Использование вычисляемых полей и ресурсов в СКД

Иногда требуется более сложная логика, например, добавление префиксов или условий при сложении строк. Рассмотрим ситуацию, когда нам нужно объединить суммы и валюты. В этом случае мы можем использовать вкладку «Вычисляемые поля».

Проанализируем ситуацию: если нам нужно выводить данные в формате «Сумма/Валюта», мы можем создать вычисляемое поле с выражением:


Строка(Сумма) + " " + СокрЛП(Валюта.Наименование)

Однако помните, что простое сложение через «+» в вычисляемом поле сработает только для строк внутри одной детальной записи. Для агрегации по группе записей всё равно придется вернуться к использованию функций СоединитьСтроки или ВычислитьВыражениеСГруппировкойМассив в ресурсах.

Метод 4. Особенности работы со строками в языке запросов

Рассмотрим важный теоретический момент, который обсуждался на форуме. Можно ли складывать строки в самом тексте запроса? Да, но только если это строки из одной и той же записи (строки таблицы).

Пример допустимого кода в запросе:


ВЫБРАТЬ
    Номенклатура.Наименование + " (код: " + Номенклатура.Код + ")" КАК ПолноеНаименование
ИЗ
    Справочник.Номенклатура КАК Номенклатура

Внимание на типы данных: В языке запросов 1С запрещено неявное преобразование типов — для безопасного извлечения данных в нужном формате есть универсальная выгрузка данных на основе произвольных запросов. Вы не можете сложить число и строку. Также существует проблема со строками неограниченной длины.

Разберем основные правила безопасной конкатенации в запросе:

Подведение итогов и рекомендации

Проанализировав все способы, можно сделать следующие выводы:

  1. Если ваша цель — отчет, всегда выбирайте СКД. Использование СоединитьСтроки(Массив(Поле), ", ") в ресурсах — это самый быстрый и надежный путь, который не требует написания сложного кода и легко поддерживается.
  2. Если вам нужно подготовить данные для программного алгоритма (например, для заполнения документа), используйте обход выборки по группировкам в коде 1С.
  3. Не пытайтесь решить задачу «склеивания» строк из разных записей внутри текста запроса (через временные таблицы и соединения) — это приведет к крайне низкой производительности и трудночитаемому коду.

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

← На главную