Как объединить строки из разных записей в одну в запросе 1С

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

В практике разработчика 1С часто возникает задача: собрать данные из нескольких строк таблицы или регистра в одну текстовую строку. Классический пример — получение списка способов отражения зарплаты для одного сотрудника, когда вместо нескольких строк (например, "Петрова — 20%" и "Петрова — 80%") нам нужно вывести одну: "Петрова — 20% / 80%".

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

Анализ проблемы: почему обычный запрос не справляется

Разберем ситуацию на примере. У нас есть регистр сведений БухучетРаспределениеОсновногоЗаработка. В нем хранятся записи о том, как распределяется зарплата сотрудника по разным аналитическим счетам. Если мы напишем простой запрос, то на каждого сотрудника получим столько строк, сколько способов отражения ему назначено. Попытка просто "сложить" поля через оператор + внутри запроса приведет лишь к склейке полей внутри одной строки, но не объединит разные записи в одну общую строку.

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


ВЫБРАТЬ
    Бухучет.Сотрудник КАК Сотрудник,
    СТРОКА(Бухучет.СпособОтражения) + " / " + СТРОКА(Бухучет.Доля) КАК Распределение
ИЗ
    РегистрСведений.БухучетРаспределениеОсновногоЗаработка КАК Бухучет

Результатом такого запроса будет список, где для одного и того же сотрудника Волкова М.С. выведутся три отдельные строки. Наша же цель — получить одну строку с перечислением всех долей через разделитель.

Решение 1: Новые строковые функции в платформе 8.3.20.1549 и выше

Долгое время в языке запросов 1С операции со строками были крайне ограничены. Однако, начиная с версии платформы 8.3.20.1549, разработчики получили в руки мощный инструментарий. Теперь мы можем выполнять приведение типов и конкатенацию (сложение) прямо в тексте запроса, что раньше вызывало ошибку "Несовместимые типы".

Рассмотрим основные функции, которые теперь доступны:

  1. СТРОКА() — позволяет преобразовать число, дату или булево значение в строку прямо в запросе.
  2. СТРЗАМЕНИТЬ() — заменяет части строки.
  3. СОКРЛП(), СОКРЛ(), СОКРП() — удаление лишних пробелов, что критично при сложении строк фиксированной длины.
  4. СТРНАЙТИ() — поиск позиции подстроки.

Хотя эти функции значительно облегчают подготовку данных, они все еще не решают задачу агрегации (объединения строк из разных записей). В SQL для этого существуют функции типа GROUP_CONCAT или STRING_AGG, но в 1С из-за необходимости поддерживать разные СУБД (MS SQL, PostgreSQL, Oracle, IBM DB2) прямого аналога в языке запросов пока нет. Для этого мы будем использовать СКД.

Решение 2: Использование функции СоединитьСтроки в СКД

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

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

  1. Создадим набор данных (запрос), в котором выберем Сотрудника, СпособОтражения и Долю.
  2. Перейдем на закладку Вычисляемые поля. Здесь мы можем подготовить фрагмент строки для каждой отдельной записи. Например, создадим поле СтрокаРаспределения с выражением:
    СТРОКА(СпособОтражения) + " " + СТРОКА(Доля) + "%"
  3. Перейдем на закладку Ресурсы. Это самый важный этап.
  4. Выберем наше поле СтрокаРаспределения. В колонке "Выражение" пропишем использование агрегатной функции: СоединитьСтроки(СтрокаРаспределения, " / ", " / ")
  5. В колонке "Рассчитывать по..." укажем только те группировки, в которых нам нужно схлопнуть строки (например, по Сотруднику).

Функция СоединитьСтроки принимает три параметра:

Решение 3: Программная обработка результата запроса

Если по каким-то причинам вы не используете СКД, задачу можно решить классическим перебором результата запроса в коде. Рассмотрим, как проанализировать ситуацию и свернуть данные вручную.

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

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

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


// Предположим, ТЗРезультат уже содержит данные из запроса
ТЗРезультат.Колонки.Добавить("ИтоговоеРаспределение", Новый ОписаниеТипов("Строка"));

ТЗ_Свернутая = ТЗРезультат.Скопировать();
ТЗ_Свернутая.Свернуть("Сотрудник", "ИтоговоеРаспределение");

Для Каждого СтрГруппировки Из ТЗ_Свернутая Цикл
    Отбор = Новый Структура("Сотрудник", СтрГруппировки.Сотрудник);
    СтрокиДетализации = ТЗРезультат.НайтиСтроки(Отбор);
    
    МассивСтрок = Новый Массив;
    Для Каждого СтрДетали Из СтрокиДетализации Цикл
        МассивСтрок.Добавить(Строка(СтрДетали.СпособОтражения) + " " + Строка(СтрДетали.Доля) + "%");
    КонецЦикла;
    
    СтрГруппировки.ИтоговоеРаспределение = СтрСоединить(МассивСтрок, " / ");
КонецЦикла;

Этот метод более трудоемкий, чем СКД, но он дает полный контроль над логикой объединения, если требуются сложные условия или специфическое форматирование чисел.

Почему в 1С нет функции GROUP_CONCAT в запросах?

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

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

Подведем итоги

Для решения задачи объединения строк из разных записей мы рекомендуем следующий алгоритм выбора метода:

  1. Основной вариант: Используйте СКД и функцию СоединитьСтроки в ресурсах. Это самый быстрый и производительный способ, не требующий написания сложного кода.
  2. Если нужна обработка в коде: Используйте связку Массив и СтрСоединить() после выгрузки результата запроса в таблицу значений.
  3. Для простых операций в одной строке: Если вам нужно просто склеить два поля одной записи (например, Фамилию и Имя), используйте оператор + и функцию СТРОКА(), если ваша версия платформы выше 8.3.20.1549.

Важный нюанс: Помните, что использование строковых функций в условиях соединения или группировки в запросе может привести к значительному замедлению работы, так как СУБД не сможет использовать индексы. Старайтесь выполнять преобразования типов в полях выбора, а не в условиях ГДЕ или ПО.

← На главную