Как сгруппировать по номенклатуре и объединить ссылки на документы в одну строку в 1С?

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

Рассмотрим достаточно распространенную задачу, с которой сталкиваются разработчики 1С при построении отчетов. Часто возникает необходимость сгруппировать данные по определенному разрезу, например, по Номенклатура, просуммировать числовые показатели (например, Количество) и при этом сохранить информацию о документах, которые сформировали эти движения. При этом мы хотим видеть все документы-регистраторы в одной ячейке через запятую, чтобы не плодить лишние строки в отчете.

Проанализируем ситуацию: если мы попытаемся сделать группировку в стандартном запросе 1С, добавив поле Ссылка в секцию СГРУППИРОВАТЬ ПО, система закономерно выдаст нам несколько строк для одной номенклатуры — по одной строке на каждый уникальный документ. Если же мы уберем ссылку из группировки, то потеряем информацию о документах. В классическом SQL для решения этой проблемы применяется функция CONCAT или STRING_AGG, однако язык запросов 1С таких функций не поддерживает. Выясним, как мы можем элегантно обойти это ограничение.

Решение 1: Использование Системы Компоновки Данных (СКД)

Самый оптимальный и "правильный" путь в экосистеме 1С — передать задачу вывода и компоновки данных в СКД. Разберем по шагам, как настроить вывод нескольких документов в одну строку.

  1. Создаем схему компоновки данных и пишем базовый запрос, в котором выбираем необходимые поля (включая ссылки на документы) без группировки по ссылке в самом тексте запроса. СКД сама сгруппирует данные на этапе вывода.
  2. Переходим на вкладку Ресурсы в настройках СКД. Именно здесь мы будем "склеивать" наши документы.
  3. В колонке "Поле" выбираем наше поле с документами (например, ДокументПоступления или Ссылка).
  4. В колонке "Выражение" прописываем специальную агрегатную функцию СКД: СоединитьСтроки(Массив(ДокументПоступления), ", ")

Разберем подробнее, как работает это выражение. Функция Массив() собирает все документы, которые относятся к текущей группировке (к конкретной номенклатуре), в коллекцию. Затем функция СоединитьСтроки() преобразует элементы этого массива в их строковые представления и объединяет в одну строку, используя указанный нами разделитель — в данном случае запятую с пробелом ", ".

Дополнительные настройки в СКД: дубли и сортировка

Посмотрим на пример, когда в результате соединения таблиц в запросе один и тот же документ задвоился для одной номенклатуры. Чтобы в итоговой строке не выводились одинаковые документы по несколько раз, мы можем модифицировать наше выражение, добавив ключевое слово Различные:

СоединитьСтроки(Массив(Различные ДокументПоступления), ", ")

Кроме того, если нам важен хронологический порядок вывода документов (чтобы они не шли вразнобой), мы можем применить функцию Упорядочить(). Выражение примет следующий вид:

СоединитьСтроки(Упорядочить(Массив(ДокументПоступления)), ", ")

После настройки ресурсов важно перейти на вкладку Настройки и задать структуру отчета. Группировку строк там нужно сделать только по полю Номенклатура. Поле с документами выведется в колонке показателей как сгруппированный текст.

Решение 2: Программный обход без использования СКД

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

Сначала мы выполняем запрос без агрегации строк по документам и выгружаем результат в ТаблицаЗначений. Затем мы должны добавить новую колонку для текстового представления списка документов и свернуть таблицу.

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Таблица.Номенклатура КАК Номенклатура,
    |    Таблица.Количество КАК Количество,
    |    Таблица.Ссылка КАК Документ
    |ИЗ
    |    Документ.ПоступлениеМЗ.Материалы КАК Таблица";

ТаблицаРезультат = Запрос.Выполнить().Выгрузить();

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

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

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

Таким образом, мы выяснили, что несмотря на ограничения самого языка запросов 1С, платформа предоставляет мощные и удобные инструменты для агрегации строк — как визуально через СКД, так и программно через обработку таблиц значений.

← На главную