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