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