В практике разработки на платформе 1С:Предприятие часто возникает задача агрегации данных: например, когда для одной номенклатуры в базе данных заведено несколько проектов, и нам нужно вывести их названия в одной ячейке через запятую. Если в классическом SQL для этого существуют встроенные функции вроде STRING_AGG или GROUP_CONCAT, то язык запросов 1С, к сожалению, не поддерживает такую операцию напрямую.
В этой статье мы подробно разберем, как обойти это ограничение, используя возможности системы компоновки данных (СКД), хитрости языка запросов и программную постобработку. Мы проанализируем различные подходы, от самых простых до наиболее производительных.
Это наиболее правильный и "цивилизованный" метод решения задачи в современной среде 1С. Платформа предоставляет специальные агрегатные функции в языке выражений СКД, которые выполняются уже на этапе компоновки результата, после получения данных из СУБД.
Рассмотрим по шагам, как настроить сбор строк в СКД:
Номенклатура и Проект).Проект в колонке "Выражение" пропишем использование функции СоединитьСтроки.Рассмотрим пример сложной формулы ресурса, которая позволяет не просто склеить строки, но и упорядочить их:
СоединитьСтроки(
ВычислитьВыражениеСГруппировкойМассив(
"Проект",
"Номенклатура"
),
", ",
""
)
Разберем, что здесь происходит:
ВычислитьВыражениеСГруппировкойМассив собирает все значения поля Проект в рамках текущей группировки Номенклатура в массив. Затем функция СоединитьСтроки берет этот массив и объединяет его элементы в одну строку, используя разделитель ", ".
Если нам нужно более сложное поведение (например, исключение дублей или специфическая сортировка), мы можем задействовать еще более мощную связку:
СоединитьСтроки(
Упорядочить(
ВычислитьВыражениеСГруппировкойМассив("Проект", "Номенклатура"),
"Проект Возр"
),
"; "
)
Иногда возможностей встроенных функций СКД недостаточно. В этом случае мы можем делегировать задачу общему модулю. Это позволяет реализовать практически любую логику обработки строк.
Алгоритм действий следующий:
РаботаСоСтроками) и установим флаги "Сервер" и "Вызов сервера".
Функция СклеитьПроекты(МассивПроектов) Экспорт
Если МассивПроектов = Неопределено Тогда
Возврат "";
КонецЕсли;
// Удаляем дубли и пустые значения
Результат = "";
Для Каждого Стр Из МассивПроектов Цикл
Если ЗначениеЗаполнено(Стр) И Найти(Результат, Стр) = 0 Тогда
Результат = Результат + ?(Результат = "", "", ", ") + Стр;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Проект вызовем нашу функцию:
РаботаСоСтроками.СклеитьПроекты(ВычислитьВыражениеСГруппировкойМассив("Проект", "Номенклатура"))
Этот метод считается наиболее гибким, так как внутри функции вы можете использовать регулярные выражения, форматирование или дополнительные проверки прав доступа.
Если использование СКД по каким-то причинам невозможно (например, данные нужны строго внутри программного кода в виде таблицы значений), и мы точно знаем, что количество объединяемых строк невелико (до 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 ИНАЧЕ "" КОНЕЦ КАК ВсеПроекты
ИЗ
втСвернуто КАК втСвернуто
Важно: Этот метод крайне не рекомендуется для больших объемов данных, так как он сильно нагружает СУБД и требует заранее известного максимального количества объединяемых элементов.
Если нам нужно вывести данные в печатную форму или специализированный отчет, самый быстрый и надежный способ — это использование предложения ИТОГИ в запросе и последующая программная обработка.
Выясним, как это реализовать:
ИТОГИ ПО.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура,
| Проект
|ИЗ
| Справочник.ПроектыНоменклатуры
|ИТОГИ ПО
| Номенклатура";
Результат = Запрос.Выполнить();
ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаНоменклатура.Следующий() Цикл
СписокПроектов = "";
ВыборкаДетальные = ВыборкаНоменклатура.Выбрать();
Пока ВыборкаДетальные.Следующий() Цикл
СписокПроектов = СписокПроектов + ?(СписокПроектов = "", "", ", ") + ВыборкаДетальные.Проект;
КонецЦикла;
// Теперь у нас есть переменная СписокПроектов, которую можно выводить в строку
Сообщить("Номенклатура: " + ВыборкаНоменклатура.Номенклатура + " Проекты: " + СписокПроектов);
КонецЦикла;
Этот подход работает быстрее всех остальных на стороне сервера 1С, так как агрегация строк происходит в памяти сервера приложений, а не в тяжелых запросах к базе данных.
Подводя итоги, проанализируем, какой метод выбрать в зависимости от ситуации:
СоединитьСтроки или внешнюю функцию общего модуля. Это стандарт платформы.ИТОГИ ПО. Это гарантирует отсутствие ошибок при большом количестве данных.STRING_AGG. Однако помните, что это делает ваш код зависимым от конкретной СУБД.Рассмотренные нами способы позволяют эффективно решать задачу объединения строк, обходя архитектурные ограничения встроенного языка запросов 1С. Выбор конкретного метода всегда зависит от контекста вашей задачи и требований к производительности системы.