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