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

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

В практике разработки на платформе 1С:Предприятие часто возникает задача: собрать несколько строковых значений из разных записей в одну общую строку. Если в языке SQL для этого существуют встроенные функции агрегации (например, STRING_AGG в PostgreSQL или FOR XML PATH в MS SQL Server), то язык запросов 1С традиционно не предоставляет прямого аналога для строк. Тем не менее, решение существует, и оно лежит в плоскости «спортивного» интереса и глубокого понимания механизмов соединений таблиц.

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

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

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

Основная сложность заключается в том, что стандартная агрегатная функция СУММА работает только с числовыми типами данных. Попытка сложить строки напрямую в секции ВЫБРАТЬ при использовании СГРУППИРОВАТЬ ПО приведет к ошибке синтаксиса. Поэтому мы будем использовать обходные пути, основанные на соединениях таблиц.

Метод последовательных левых соединений

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

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


ВЫБРАТЬ
    Т1.Ссылка КАК Ссылка,
    Т1.Код + ЕСТЬNULL(Т2.Код, "") + ЕСТЬNULL(Т3.Код, "") КАК ОбъединеннаяСтрока
ИЗ
    Справочник.Номенклатура КАК Т1
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Т2 
        ПО Т1.Ссылка = Т2.Ссылка И Т1.Код < Т2.Код
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Т3 
        ПО Т2.Ссылка = Т3.Ссылка И Т2.Код < Т3.Код
ГДЕ
    Т1.Ссылка = &Ссылка

В данном примере мы используем условие Т1.Код < Т2.Код, чтобы обеспечить уникальность выбираемых значений в цепочке. Важно помнить: этот метод требует жесткого прописывания количества соединений в тексте запроса. Если строк окажется больше, чем соединений, часть данных будет потеряна. Если меньше — функция ЕСТЬNULL поможет избежать превращения всей строки в NULL.

Метод бинарного дерева соединений (для продвинутых задач)

Если количество строк может быть значительным (например, до 32 или 64), использование последовательных соединений сделает текст запроса нечитаемым и крайне медленным. В таких случаях мы рекомендуем использовать «бинарное дерево». Смысл метода заключается в том, чтобы соединять строки парами, затем полученные пары соединять между собой, превращая их в четверки, и так далее.

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

  1. Подготавливаем временную таблицу с порядковыми номерами строк для каждого объекта.
  2. Выполняем соединение пар: 1-я строка со 2-й, 3-я с 4-й.
  3. На следующем этапе соединяем результат первой пары с результатом второй пары (получаем склейку 1-2-3-4).
  4. Продолжаем до достижения нужной глубины (2, 4, 8, 16, 32...).

Этот метод позволяет за 5-6 этапов соединений склеить до 64 строк, что покрывает большинство практических задач. Однако стоит учитывать, что итоговый запрос будет весьма громоздким и сложным для отладки.

Использование конструкции ВЫБОР КОГДА

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

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


ВЫБРАТЬ
    Т.Ссылка КАК Ссылка,
    МАКСИМУМ(ВЫБОР КОГДА Т.Код = "А" ТОГДА "А" ИНАЧЕ "" КОНЕЦ) + 
    МАКСИМУМ(ВЫБОР КОГДА Т.Код = "Б" ТОГДА "Б" ИНАЧЕ "" КОНЕЦ) КАК РезультирующаяСтрока
ИЗ
    Справочник.Номенклатура КАК Т
СГРУППИРОВАТЬ ПО
    Т.Ссылка

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

Почему в 1С нет универсальной функции конкатенации?

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

Язык запросов 1С является универсальным (транслируемым). Поскольку на момент проектирования платформы единого стандарта SQL для агрегации строк не существовало, разработчики 1С не включили подобную функцию в транслятор, чтобы обеспечить идентичное поведение запросов на всех поддерживаемых СУБД.

Ограничения и рекомендации

При использовании вышеописанных методов следует учитывать несколько важных моментов:

  1. Длина строки: В запросах 1С результат сложения строк может быть ограничен длиной 1024 символа. Если итоговая строка окажется длиннее, она может быть обрезана.
  2. Производительность: Большое количество левых соединений (LEFT JOIN) существенно нагружает планировщик запросов СУБД. Не рекомендуется использовать такие методы для массовой выборки данных (например, для построения отчета по всем товарам склада).
  3. Альтернатива: Если условие «только запрос» не является жестким требованием (как в случае «спортивного интереса»), всегда лучше использовать постобработку результата запроса в коде 1С или встроенную функцию СКД (Системы компоновки данных) СоединитьСтроки().

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

Подведем итог: объединить значения из колонки в строку только запросом возможно, если количество значений ограничено и структура запроса подготовлена заранее под это количество. Для произвольного количества строк универсального решения «в один запрос» без использования динамического формирования текста запроса на языке 1С не существует.

← На главную