В практике разработчика 1С часто возникает задача: собрать данные из нескольких строк таблицы или регистра в одну текстовую строку. Классический пример — получение списка способов отражения зарплаты для одного сотрудника, когда вместо нескольких строк (например, "Петрова — 20%" и "Петрова — 80%") нам нужно вывести одну: "Петрова — 20% / 80%".
В этой статье мы подробно разберем, почему стандартный язык запросов 1С имеет ограничения в этом вопросе, какие новые возможности появились в последних версиях платформы и как правильно реализовать объединение строк с помощью Системы компоновки данных (СКД).
Разберем ситуацию на примере. У нас есть регистр сведений БухучетРаспределениеОсновногоЗаработка. В нем хранятся записи о том, как распределяется зарплата сотрудника по разным аналитическим счетам. Если мы напишем простой запрос, то на каждого сотрудника получим столько строк, сколько способов отражения ему назначено. Попытка просто "сложить" поля через оператор + внутри запроса приведет лишь к склейке полей внутри одной строки, но не объединит разные записи в одну общую строку.
Проанализируем пример кода, который часто вызывает затруднения у новичков:
ВЫБРАТЬ
Бухучет.Сотрудник КАК Сотрудник,
СТРОКА(Бухучет.СпособОтражения) + " / " + СТРОКА(Бухучет.Доля) КАК Распределение
ИЗ
РегистрСведений.БухучетРаспределениеОсновногоЗаработка КАК Бухучет
Результатом такого запроса будет список, где для одного и того же сотрудника Волкова М.С. выведутся три отдельные строки. Наша же цель — получить одну строку с перечислением всех долей через разделитель.
Долгое время в языке запросов 1С операции со строками были крайне ограничены. Однако, начиная с версии платформы 8.3.20.1549, разработчики получили в руки мощный инструментарий. Теперь мы можем выполнять приведение типов и конкатенацию (сложение) прямо в тексте запроса, что раньше вызывало ошибку "Несовместимые типы".
Рассмотрим основные функции, которые теперь доступны:
СТРОКА() — позволяет преобразовать число, дату или булево значение в строку прямо в запросе.СТРЗАМЕНИТЬ() — заменяет части строки.СОКРЛП(), СОКРЛ(), СОКРП() — удаление лишних пробелов, что критично при сложении строк фиксированной длины.СТРНАЙТИ() — поиск позиции подстроки.Хотя эти функции значительно облегчают подготовку данных, они все еще не решают задачу агрегации (объединения строк из разных записей). В SQL для этого существуют функции типа GROUP_CONCAT или STRING_AGG, но в 1С из-за необходимости поддерживать разные СУБД (MS SQL, PostgreSQL, Oracle, IBM DB2) прямого аналога в языке запросов пока нет. Для этого мы будем использовать СКД.
Наиболее правильным и эффективным способом решения задачи "Петрова: Отражение1 / Отражение2" является использование Системы компоновки данных. В СКД существует специальная агрегатная функция СоединитьСтроки(), которая создана именно для таких случаев.
Разберем по шагам, как это настроить:
Сотрудника, СпособОтражения и Долю.СтрокаРаспределения с выражением:
СТРОКА(СпособОтражения) + " " + СТРОКА(Доля) + "%"СтрокаРаспределения. В колонке "Выражение" пропишем использование агрегатной функции:
СоединитьСтроки(СтрокаРаспределения, " / ", " / ")
Сотруднику).Функция СоединитьСтроки принимает три параметра:
Если по каким-то причинам вы не используете СКД, задачу можно решить классическим перебором результата запроса в коде. Рассмотрим, как проанализировать ситуацию и свернуть данные вручную.
Алгоритм действий будет следующим:
ТаблицуЗначений.Пример кода для программной реализации:
// Предположим, ТЗРезультат уже содержит данные из запроса
ТЗРезультат.Колонки.Добавить("ИтоговоеРаспределение", Новый ОписаниеТипов("Строка"));
ТЗ_Свернутая = ТЗРезультат.Скопировать();
ТЗ_Свернутая.Свернуть("Сотрудник", "ИтоговоеРаспределение");
Для Каждого СтрГруппировки Из ТЗ_Свернутая Цикл
Отбор = Новый Структура("Сотрудник", СтрГруппировки.Сотрудник);
СтрокиДетализации = ТЗРезультат.НайтиСтроки(Отбор);
МассивСтрок = Новый Массив;
Для Каждого СтрДетали Из СтрокиДетализации Цикл
МассивСтрок.Добавить(Строка(СтрДетали.СпособОтражения) + " " + Строка(СтрДетали.Доля) + "%");
КонецЦикла;
СтрГруппировки.ИтоговоеРаспределение = СтрСоединить(МассивСтрок, " / ");
КонецЦикла;
Этот метод более трудоемкий, чем СКД, но он дает полный контроль над логикой объединения, если требуются сложные условия или специфическое форматирование чисел.
Выясним причину отсутствия этой функции на уровне платформы. Платформа 1С:Предприятие позиционируется как кроссплатформенная среда. Разные системы управления базами данных реализуют агрегацию строк совершенно по-разному:
FOR XML PATH, в новых версиях появилась STRING_AGG.string_agg.LISTAGG.Для того чтобы запрос 1С работал одинаково на любой из этих СУБД, разработчики платформы должны создать универсальную абстракцию. Пока такая абстракция реализована только на уровне СКД в виде функции СоединитьСтроки, которая выполняется уже на уровне сервера приложений 1С после получения данных из СУБД.
Для решения задачи объединения строк из разных записей мы рекомендуем следующий алгоритм выбора метода:
СоединитьСтроки в ресурсах. Это самый быстрый и производительный способ, не требующий написания сложного кода.Массив и СтрСоединить() после выгрузки результата запроса в таблицу значений.+ и функцию СТРОКА(), если ваша версия платформы выше 8.3.20.1549.Важный нюанс: Помните, что использование строковых функций в условиях соединения или группировки в запросе может привести к значительному замедлению работы, так как СУБД не сможет использовать индексы. Старайтесь выполнять преобразования типов в полях выбора, а не в условиях ГДЕ или ПО.