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