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