В практике разработчика 1С часто возникает задача, когда при группировке данных необходимо не суммировать числовые показатели, а «склеить» строковые значения. Например, если у нас есть несколько накладных по одной номенклатуре, мы хотим видеть одну строку с названием товара, общую сумму и перечисление номеров всех накладных через запятую. Стандартный язык запросов 1С, в отличие от некоторых диалектов SQL (где есть функции string_agg или LISTAGG), не поддерживает агрегацию строк напрямую. В этой статье мы подробно разберем все доступные способы решения этой задачи: от использования Системы компоновки данных (СКД) до программной обработки результата.
Это самый современный и эффективный способ, если ваш отчет строится на базе Системы компоновки данных (СКД) — для отладки и тестирования подобных приемов есть инструменты разработчика с консолью запросов и СКД. В СКД существуют встроенные функции агрегации, которые работают уже после выполнения основного запроса к базе данных.
Рассмотрим по шагам, как это реализовать:
НомерНакладной.
СоединитьСтроки(Массив(НомерНакладной), ", ")
Проанализируем, как работает эта формула. Функция Массив() собирает все значения номеров накладных, попавших в текущую группировку, в коллекцию. Затем функция СоединитьСтроки() берет этот массив и объединяет все его элементы в одну строку, используя указанный разделитель (в нашем примере — запятая и пробел).
Важный нюанс: если вы хотите, чтобы номера в строке не повторялись, в последних версиях платформы можно использовать дополнительные параметры или предварительную обработку данных, но стандартная связка СоединитьСтроки(Массив(...)) обычно закрывает 90% потребностей бизнеса.
Если по каким-то причинам вы не можете использовать СКД или вам нужно получить готовую таблицу значений для дальнейших манипуляций в коде, следует применить метод обхода выборки. Мы не пытаемся «склеить» строки в самом запросе, а делаем это при чтении данных.
Разберем алгоритм реализации:
ТаблицаЗначений, в которую будем записывать результат.СледующийПоЗначениюПоля для эффективного обхода.Пример программного кода для реализации такой логики:
// Предположим, ЗапросРезультат уже получен и содержит поля: Номенклатура, НомерНакладной, Сумма
ВыборкаНоменклатура = ЗапросРезультат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Номенклатура");
Пока ВыборкаНоменклатура.Следующий() Цикл
СтрокаНомеров = "";
ОбщаяСумма = 0;
ВыборкаДетали = ВыборкаНоменклатура.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
// Накапливаем номера накладных
Разделитель = ?(ЗначениеЗаполнено(СтрокаНомеров), ", ", "");
СтрокаНомеров = СтрокаНомеров + Разделитель + СокрЛП(ВыборкаДетали.НомерНакладной);
// Суммируем суммы
ОбщаяСумма = ОбщаяСумма + ВыборкаДетали.Сумма;
КонецЦикла;
// Добавляем результат в итоговую таблицу
НоваяСтрока = ТаблицаРезультат.Добавить();
НоваяСтрока.Номенклатура = ВыборкаНоменклатура.Номенклатура;
НоваяСтрока.НомераНакладных = "№" + СтрокаНомеров;
НоваяСтрока.Сумма = ОбщаяСумма;
КонецЦикла;
Этот метод универсален и работает на любой версии платформы 1С:Предприятие 8 — для разработки и отладки таких алгоритмов пригодится инструмент пошаговой отладки программного кода 1С.
Иногда требуется более сложная логика, например, добавление префиксов или условий при сложении строк. Рассмотрим ситуацию, когда нам нужно объединить суммы и валюты. В этом случае мы можем использовать вкладку «Вычисляемые поля».
Проанализируем ситуацию: если нам нужно выводить данные в формате «Сумма/Валюта», мы можем создать вычисляемое поле с выражением:
Строка(Сумма) + " " + СокрЛП(Валюта.Наименование)
Однако помните, что простое сложение через «+» в вычисляемом поле сработает только для строк внутри одной детальной записи. Для агрегации по группе записей всё равно придется вернуться к использованию функций СоединитьСтроки или ВычислитьВыражениеСГруппировкойМассив в ресурсах.
Рассмотрим важный теоретический момент, который обсуждался на форуме. Можно ли складывать строки в самом тексте запроса? Да, но только если это строки из одной и той же записи (строки таблицы).
Пример допустимого кода в запросе:
ВЫБРАТЬ
Номенклатура.Наименование + " (код: " + Номенклатура.Код + ")" КАК ПолноеНаименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
Внимание на типы данных: В языке запросов 1С запрещено неявное преобразование типов — для безопасного извлечения данных в нужном формате есть универсальная выгрузка данных на основе произвольных запросов. Вы не можете сложить число и строку. Также существует проблема со строками неограниченной длины.
Разберем основные правила безопасной конкатенации в запросе:
ВЫРАЗИТЬ(... КАК СТРОКА(100)), если работаете с полями неограниченной длины или не уверены в типе.Число или Дата в Строка непосредственно в запросе практически невозможно (кроме очень громоздких конструкций ВЫБОР КОГДА).NULL (например, при левом соединении), обязательно используйте функцию ЕСТЬNULL(Поле, ""), иначе результат сложения всей строки станет NULL.Проанализировав все способы, можно сделать следующие выводы:
СоединитьСтроки(Массив(Поле), ", ") в ресурсах — это самый быстрый и надежный путь, который не требует написания сложного кода и легко поддерживается.Выяснив причину ограничений платформы (отсутствие агрегатной функции для строк в SDBL), мы понимаем, что наиболее правильный подход — разделение ответственности: запрос получает «сырые» данные, а механизмы СКД или программный код занимаются их оформлением и представлением в нужном виде.