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