К статье
Практический материал

Разработка и Конфигурация · 10 мин

Порядок обхода в 1С: как работает обход выборки запроса

Что такое порядок обхода в 1С: виды обхода результата запроса, методы Выбрать() и Обойти(), итоги по группировкам, примеры кода и типичные ошибки разработчиков.

Порядок обхода в 1С — это способ последовательного перебора записей результата запроса при программной обработке данных. Когда разработчик выполняет запрос и получает результат, платформа предоставляет объект «Выборка из результата запроса», по которому нужно пройтись в цикле. То, в каком порядке будут поступать записи — по строкам, по группировкам, с итогами или без — и определяется параметрами обхода.

Термин чаще всего встречается в двух контекстах. Первый — метод Выбрать() результата запроса, который принимает параметр «ТипОбходаРезультатаЗапроса». Второй — конструкция запроса ИТОГИ ПО, после которой обход по группировкам становится основным способом получить итоговые данные. Понимание порядка обхода напрямую влияет на корректность отчётов, обработок и любых механизмов, читающих данные запросом.

Ошибки в выборе порядка обхода приводят к типичным дефектам: итоги считаются дважды, детальные строки пропускаются, иерархические справочники обходятся «вперемешку». Ниже разобраны виды обхода, синтаксис, практические сценарии и способы проверить результат.

Что такое выборка и зачем нужен порядок обхода

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

Если запрос простой, без итогов, порядок обхода всегда линейный: записи идут одна за другой в порядке сортировки запроса. Но когда в запросе используется ИТОГИ ПО, результат становится многоуровневым: есть строки группировок (итоги) и детальные записи внутри них. Именно здесь порядок обхода определяет, увидите ли вы итоговые строки, вложенные группы и детали — и в какой последовательности.

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

Метод Выбрать() принимает параметр типа «ТипОбходаРезультатаЗапроса» с тремя основными значениями. Выбор значения должен соответствовать структуре запроса, иначе данные будут прочитаны неполно или некорректно.

Тип обходаЧто возвращаетКогда применять
ПрямойВсе записи последовательно, без учёта группировокЗапросы без ИТОГИ или когда итоги не нужны
ПоГруппировкамТолько строки группировок; детали получаются вложенной выборкойЗапросы с ИТОГИ ПО, когда нужны итоги по уровням
ПоГруппировкамСИерархиейСтроки группировок с учётом иерархии справочниковИерархические данные: номенклатура с папками, подразделения

Важное следствие: при обходе «ПоГруппировкам» детальные записи в основном цикле не попадаются. Их нужно читать через вложенную выборку — метод Выборка.Выбрать() внутри цикла вернёт детали текущей группы. Это двухуровневая модель чтения, и она принципиально отличается от линейного перебора.

Синтаксис и примеры кода

Простейший линейный обход без итогов выглядит так:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Товар,

| Номенклатура.Код КАК Код

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|УПОРЯДОЧИТЬ ПО

| Код";

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

Сообщить(Выборка.Код + " — " + Выборка.Товар);

КонецЦикла;

Обход по группировкам с вложенными деталями:

Запрос.Текст =

"ВЫБРАТЬ

| Продажи.Номенклатура КАК Товар,

| СУММА(Продажи.Количество) КАК Количество

|ИЗ

| РегистрНакопления.Продажи КАК Продажи

|СГРУППИРОВАТЬ ПО

| Продажи.Номенклатура

|ИТОГИ СУММА(Количество) ПО

| Товар";

ВыборкаПоГруппам = Запрос.Выполнить().Выбрать(

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

Пока ВыборкаПоГруппам.Следующий() Цикл

Сообщить("Группа: " + ВыборкаПоГруппам.Товар

+ ", итого: " + ВыборкаПоГруппам.Количество);

Детали = ВыборкаПоГруппам.Выбрать();

Пока Детали.Следующий() Цикл

// обработка детальной записи

КонецЦикла;

КонецЦикла;

Обход по группировкам и иерархии

Тип обхода «ПоГруппировкамСИерархией» нужен, когда группировка построена по иерархическому справочнику и требуется обойти дерево сверху вниз: сначала родительская папка, затем вложенные элементы. Платформа сама формирует строки иерархических уровней, если в запросе указано ИТОГИ ПО Товар ИЕРАРХИЯ или группировка по полю с иерархией.

Типичный сценарий — отчёт по остаткам склада, где номенклатура разбита по папкам. С обходом «ПоГруппировкамСИерархией» вы получаете строку папки с суммарным остатком, затем вложенные элементы. При этом у записи можно проверить Выборка.ТипЗаписи(): она вернёт «ИтогПоГруппировке», «ИтогПоИерархии» или «ДетальнаяЗапись», что позволяет строить разную логику для разных уровней.

Ограничение: обход с иерархией требует, чтобы группировочное поле действительно было ссылкой на иерархический объект. Для неиерархических данных этот тип обхода не даст преимуществ и только усложнит код.

Порядок действий
  1. 1
    Определите, нужны ли итоги: если да — добавьте в запрос ИТОГИ ПО с нужными полями группировки
  2. 2
    Выберите тип обхода: Прямой для плоских данных, ПоГруппировкам для итогов, ПоГруппировкамСИерархией для деревьев
  3. 3
    Напишите цикл Пока Выборка.Следующий() с вложенной выборкой для детальных записей
  4. 4
    Проверьте результат на контрольном наборе данных: суммы итогов должны сходиться с суммами деталей

Как проверить корректность обхода

Простейший способ убедиться, что обход выбран правильно, — сличить количество обработанных записей и контрольные суммы. Если запрос содержит итоги, сумма по группе должна равняться сумме её детальных строк; расхождение означает, что часть данных потеряна или учтена дважды.

Полезно временно выводить в отладку тип каждой записи через Выборка.ТипЗаписи() и уровень группировки через Выборка.Уровень(). Это сразу показывает, попадают ли в цикл итоговые строки, которые вы не собирались обрабатывать, — самая частая причина «удвоенных» итогов в отчётах.

Контрольные точки

Как проверить результат

Сумма итога по группе
Норма

Равна сумме детальных записей группы

Тревожный признак

Итог больше или меньше — детали обрабатываются не все или дважды

Количество обработанных строк
Норма

Совпадает с числом строк результата запроса в консоли

Тревожный признак

Меньше — часть записей пропущена из-за неверного типа обхода

Тип записи в цикле
Норма

Обрабатываются только нужные типы (детали или итоги)

Тревожный признак

В расчёт попадают итоговые строки как обычные данные

Типичные ошибки и их последствия

Самая распространённая ошибка — суммировать значения при прямом обходе запроса с итогами. В линейной выборке итоговые строки выглядят как обычные записи, и их значения добавляются к деталям, удваивая или утраивая суммы. Признак: итог отчёта кратно превышает ожидаемый.

Вторая ошибка — обход «ПоГруппировкам» без вложенной выборки деталей. Разработчик видит только строки групп и удивляется, куда пропали детальные данные. Третья — попытка получить иерархию прямым обходом: порядок записей тогда не гарантирует, что родитель идёт перед дочерним элементом, и логика построения дерева ломается.

Типичные ошибки
01
Прямой обход запроса с ИТОГИ ПО — итоговые строки суммируются как детали, итоги задваиваются
02
Обход ПоГруппировкам без вложенной выборки — детальные записи полностью теряются
03
Игнорирование ТипЗаписи() — общие итоги обрабатываются наравне с группами
04
Использование ПоГруппировкамСИерархией для неиерархических данных — лишняя сложность без выигрыша
Маршрут решения

Как выбрать действие

Запрос без итогов, нужны все строки подрядИспользуйте прямой обход: Выбрать() без параметров
Нужны итоги по одному или нескольким измерениямДобавьте ИТОГИ ПО и обходите ПоГруппировкам с вложенной выборкой деталей
Данные иерархические (папки справочника, дерево подразделений)Используйте ПоГруппировкамСИерархией и проверяйте ТипЗаписи()
Нужна только сводная таблица без программной обработкиРассмотрите СКД или сводную таблицу вместо ручного обхода выборки

Альтернативы программному обходу

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

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

Итог

Что важно запомнить

Порядок обхода определяет, какие строки выборки и в какой последовательности попадут в цикл. Тип обхода должен соответствовать запросу: прямой — без итогов, ПоГруппировкам — с ИТОГИ ПО, ПоГруппировкамСИерархией — для деревьев. Контролируйте результат через ТипЗаписи() и сверку сумм итогов с деталями.

Частые вопросы

Чем отличается Выбрать() от Выгрузить()?

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

Почему при обходе по группировкам не видно детальных записей?

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

Как узнать, что текущая запись — итог, а не деталь?

Используйте метод Выборка.ТипЗаписи(): он возвращает значения вида «ДетальнаяЗапись», «ИтогПоГруппировке», «ИтогПоИерархии» или «ОбщийИтог». Дополнительно метод Уровень() показывает глубину текущей группировки.

Можно ли обойти выборку повторно после завершения цикла?

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

Влияет ли УПОРЯДОЧИТЬ ПО на порядок обхода?

Да, при любом типе обхода записи внутри своего уровня идут в порядке сортировки запроса. Если УПОРЯДОЧИТЬ ПО не указано, порядок записей не гарантирован и может меняться между выполнениями — на это нельзя закладываться в логике.

Когда вместо ручного обхода лучше использовать СКД?

Когда задача сводится к отчёту с группировками, итогами и отборами без сложной построчной логики. СКД сама выполняет обход и расчёт итогов, а настройки можно менять без изменения кода. Ручной обход оставьте для случаев, где каждая строка требует программных действий.