Как работает обход по группировкам результата запроса в 1С 8 по сравнению с 7.7?

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

При переходе с платформы 1С:Предприятие 7.7 на 1С 8.x многие разработчики сталкиваются с трудностями при обработке результатов запроса. Привычные методы работы с группировками перестают функционировать, и попытки получить лесенку данных часто приводят к ошибкам или «плоским» таблицам. Разберем по шагам, в чем заключается ключевое отличие логики новых версий и как правильно реализовать обход. База для самоучителя языка запросов — для этого пригодится консоль запросов и кода для разработчика.

Ключевое отличие логики 1С 8 от 1С 7.7

В версии 1С 7.7 обход осуществлялся с помощью встроенного в сам запрос метода Группировка(), где в цикле указывался номер или имя группировки. Запрос неявно строил итоги самостоятельно, и код выглядел как последовательный вызов функций самого объекта запроса.

В платформе 1С 8.x подход стал объектно-ориентированным. Теперь результат запроса представляет собой древовидную структуру (если были запрошены итоги), а обход вложенных группировок выполняется не от исходного объекта результата, а от текущей записи выборки верхнего уровня. Проанализируем ситуацию: чтобы получить вложенную выборку, вам нужно применить метод Выбрать() к родительскому узлу, а не к корню.

Разница между конструкциями СГРУППИРОВАТЬ ПО и ИТОГИ ПО

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


ВЫБРАТЬ 
    РеализацияТоваровУслугТовары.Ссылка.Соглашение.Менеджер КАК Менеджер, 
    РеализацияТоваровУслугТовары.Ссылка.Партнер КАК Партнер, 
    РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура, 
    СУММА(РеализацияТоваровУслугТовары.Количество) КАК Количество 
ИЗ 
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары 
СГРУППИРОВАТЬ ПО 
    РеализацияТоваровУслугТовары.Ссылка.Соглашение.Менеджер, 
    РеализацияТоваровУслугТовары.Ссылка.Партнер, 
    РеализацияТоваровУслугТовары.Номенклатура

Такой код в 1С 8 просто сворачивает дублирующиеся строки и выдает плоскую таблицу. Никакой иерархии здесь нет. Для того чтобы результат приобрел древовидную структуру, и платформа добавила специальные итоговые записи (узлы) для каждой группировки, необходимо использовать блок ИТОГИ ПО. Для визуальной проверки и отладки запросов с группировками пригодится консоль запросов для управляемых форм.

Исправленный вариант текста запроса, который формирует правильную структуру, выглядит так:


ВЫБРАТЬ 
    РеализацияТоваровУслугТовары.Ссылка.Соглашение.Менеджер КАК Менеджер, 
    РеализацияТоваровУслугТовары.Ссылка.Партнер КАК Партнер, 
    РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура, 
    РеализацияТоваровУслугТовары.Количество КАК Количество 
ИЗ 
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары 
УПОРЯДОЧИТЬ ПО 
    Менеджер, 
    Партнер, 
    Номенклатура 
ИТОГИ СУММА(Количество) ПО 
    Менеджер, 
    Партнер, 
    Номенклатура

Виды обхода результата запроса в 1С 8

Метод Выбрать() в платформе 8.x может принимать тип обхода (системное перечисление ОбходРезультатаЗапроса). Посмотрим на доступные варианты:

  1. Прямой (используется по умолчанию) — линейный обход всех записей подряд в плоском виде, включая детальные и итоговые записи вперемешку, как они идут в результате.
  2. ПоГруппировкам — обход только родительских записей текущего уровня. Именно этот вид используется для классической лесенки циклов «Менеджер -> Контрагент -> Детальные записи».
  3. ПоГруппировкамСИерархией — используется для иерархических справочников (при наличии конструкции ИТОГИ ПО ... ТОЛЬКО ИЕРАРХИЯ).

Правильный синтаксис вложенного обхода (пример)

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


// Получаем выборку самого верхнего уровня (Менеджеры)
ВыборкаМенеджер = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Менеджер");
Пока ВыборкаМенеджер.Следующий() Цикл
    // Выводим данные менеджера
    
    // Получаем выборку вложенного уровня, вызывая метод "Выбрать" у ТЕКУЩЕЙ выборки менеджера
    ВыборкаПартнер = ВыборкаМенеджер.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Партнер");
    Пока ВыборкаПартнер.Следующий() Цикл
        // Выводим данные партнера
        
        // Получаем детальные записи (нижний уровень номенклатуры)
        ВыборкаДетальные = ВыборкаПартнер.Выбрать(); // по умолчанию обход Прямой
        Пока ВыборкаДетальные.Следующий() Цикл
            // Выводим номенклатуру и количество
        КонецЦикла;
    КонецЦикла;
КонецЦикла;

Второй параметр метода Выбрать() — это имя группировки (например, "Партнер"). Его указывать не обязательно, если вы спускаетесь ровно на один уровень вниз согласно тексту запроса, но явное указание защищает ваш алгоритм от неожиданных ошибок при изменении порядка полей в будущем.

Альтернативный способ работы: Дерево Значений

Если построение многоуровневых циклов Пока ... Следующий() кажется избыточным для текущей задачи, в 1С 8 существует прекрасная альтернатива. Результат запроса, содержащий итоги, можно в одну строку выгрузить в специальный универсальный объект коллекции — ДеревоЗначений — для этого подойдёт универсальная выгрузка данных из запросов любой сложности.

Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

В версии 1С 7.7 подобного встроенного механизма не было. Полученное Дерево Значений можно обходить рекурсивно, сразу передавать на форму для отображения пользователю или манипулировать его строками (узлами) напрямую в оперативной памяти.

← На главную