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

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

Как обратиться к результату запроса в 1С

Как обратиться к результату запроса в 1С: Выгрузить, Выбрать, обход выборки, обращение к полям по имени и индексу, проверка на пустоту. Примеры кода и типичные ошибки.

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

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

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

Получение результата запроса: базовая последовательность

Прежде чем обращаться к данным, нужно корректно выполнить запрос. Минимальный рабочий фрагмент выглядит так:

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

РезультатЗапроса = Запрос.Выполнить();

Объект РезультатЗапроса — это не сами данные, а «контейнер» с набором колонок и служебной информацией. Обратиться к значению напрямую, например РезультатЗапроса.Наименование, нельзя — сначала нужно получить выборку или выгрузить данные.

Если запрос содержит несколько пакетов (несколько операторов ВЫБРАТЬ через разделитель «;»), метод Выполнить() вернёт только последний результат. Для доступа ко всем пакетам используется метод ВыполнитьПакет(), который возвращает массив результатов, и обращение идёт по индексу: Результаты[0], Результаты[1].

Обход результата через метод Выбрать()

Метод Выбрать() возвращает объект «ВыборкаИзРезультатаЗапроса» — курсор, который перемещается по строкам последовательно. Данные читаются порциями по мере обхода, поэтому этот способ экономит память на больших объёмах.

Выборка = РезультатЗапроса.Выбрать();

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

Сообщить(Выборка.Наименование);

КонецЦикла;

Метод Следующий() возвращает булево: Истина, если строка получена, и Ложь, когда строки закончились. Обращение к полям происходит по имени через точку (Выборка.Наименование) или по индексу через квадратные скобки (Выборка[0]). Индексация начинается с нуля и соответствует порядку полей в секции ВЫБРАТЬ.

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

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

Если запрос содержит итоги (ИТОГИ ПО) или иерархию, передайте в Выбрать() параметр обхода:

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

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

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

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

// детальные записи внутри группы

КонецЦикла;

КонецЦикла;

Из строки группировки методом Выбрать() получают вложенную выборку детальных записей. Такой подход удобен для формирования иерархических отчётов без дополнительных запросов.

Выгрузка результата в таблицу значений

Метод Выгрузить() загружает весь результат в память в виде таблицы значений. Это удобно, когда нужен произвольный доступ к строкам по индексу, поиск, сортировка, свёртка или многократный обход:

ТаблицаРезультат = РезультатЗапроса.Выгрузить();

Для Каждого Строка Из ТаблицаРезультат Цикл

Сообщить(Строка.Наименование);

КонецЦикла;

// обращение к конкретной строке и колонке

Если ТаблицаРезультат.Количество() > 0 Тогда

ПервоеЗначение = ТаблицаРезультат[0]["Наименование"];

КонецЕсли;

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

Выбрать или Выгрузить

Выбрать()

Подходит для больших выборок и однократного последовательного обхода. Экономит память, но не позволяет вернуться к предыдущим строкам.

Выгрузить()

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

Выгрузить в дерево

Подходит для иерархических данных (ИТОГИ ПО, иерархия справочников). Даёт готовую структуру для дерева на форме.

Проверка результата на пустоту

Обращение к полям выборки без проверки — частый источник ошибок. Если запрос ничего не вернул, попытка прочитать значение приведёт либо к неопределённому поведению, либо к исключению в зависимости от контекста. Перед обращением используйте метод Пустой():

Если РезультатЗапроса.Пустой() Тогда

Возврат;

КонецЕсли;

Выборка = РезультатЗапроса.Выбрать();

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

НайденнаяСсылка = Выборка.Ссылка;

Когда нужно получить единственную строку (например, поиск по коду), достаточно один раз вызвать Следующий() и проверить его возвращаемое значение — это надёжнее, чем полагаться на то, что запись точно существует:

Выборка = РезультатЗапроса.Выбрать();

Если Выборка.Следующий() Тогда

Цена = Выборка.Цена;

Иначе

Цена = 0;

КонецЕсли;

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

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

РезультатЗапроса.Пустой()
Норма

Возвращает Ложь — данные есть, можно обходить

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

Возвращает Истина — запрос ничего не нашёл, обращаться к полям нельзя

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

Возвращает Истина — строка получена, поля доступны

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

Возвращает Ложь — строк нет, чтение полей даст ошибку или пустое значение

Колонки результата
Норма

Имя поля совпадает с псевдонимом в запросе (КАК Имя)

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

Обращение к несуществующему имени вызывает исключение «Поле не найдено»

Обращение к полям: по имени, по индексу, через структуру

Способ обращения к значениям зависит от того, как получены данные. В выборке и в строке таблицы значений доступны оба варианта — по имени и по индексу:

// по имени (псевдоним из запроса)

Значение1 = Выборка.Наименование;

// по индексу (порядок полей в ВЫБРАТЬ, с нуля)

Значение2 = Выборка[0];

Обращение по имени читаемее и устойчиво к изменению порядка полей в запросе. Обращение по индексу быстрее в узких циклах, но ломается при любой правке секции ВЫБРАТЬ — используйте его осознанно.

Если данные переносятся дальше по коду, удобно собрать строку выборки в структуру. Это снимает зависимость от времени жизни выборки и упрощает передачу между процедурами:

ДанныеСтроки = Новый Структура;

Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл

ДанныеСтроки.Вставить(Колонка.Имя, Выборка[Колонка.Имя]);

КонецЦикла;

Всегда задавайте полям запроса явные псевдонимы через КАК, особенно для вычисляемых выражений и полей с точкой (Номенклатура.Наименование). Без псевдонима имя колонки может оказаться неочевидным, и обращение по имени станет невозможным.
ПЗ
Практическое замечание

Работа с параметрами и временными таблицами

На состав результата влияют параметры запроса. Неустановленный параметр — типичная причина «пустого» результата там, где данные на самом деле есть. Параметры задаются до выполнения:

Запрос.УстановитьПараметр("Период", ТекущаяДатаСеанса());

Запрос.УстановитьПараметр("Организация", Организация);

При использовании менеджера временных таблиц результат каждого пакета доступен через ВыполнитьПакет(). Частый сценарий: первый запрос помещает данные во временную таблицу, второй читает из неё. Обращение к нужному результату идёт по индексу массива, при этом промежуточные пакеты типа «УНИЧТОЖИТЬ» тоже занимают позицию в массиве — учитывайте это при нумерации.

Порядок действий
  1. 1
    Создайте объект Запрос и задайте текст с явными псевдонимами полей (КАК)
  2. 2
    Установите все параметры через УстановитьПараметр
  3. 3
    Выполните запрос: Результат = Запрос.Выполнить()
  4. 4
    Проверьте Результат.Пустой() перед обращением к данным
  5. 5
    Получите выборку через Выбрать() или таблицу через Выгрузить()
  6. 6
    Обходите строки и читайте поля по имени или индексу
  7. 7
    Убедитесь на тестовых данных, что пустой результат обрабатывается без ошибок

Типичные ошибки и ограничения

Первая группа ошибок связана с обращением к несуществующим полям. Имя колонки результата — это псевдоним из запроса, а не путь через точку. Если в тексте написано Номенклатура.Наименование без КАК, обращение Выборка.НоменклатураНаименование может не сработать в зависимости от платформы — задавайте псевдонимы явно.

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

Третья группа — производительность. Выгрузка в таблицу значений результата на сотни тысяч строк расходует заметный объём памяти сервера. Если нужен только последовательный обход, используйте выборку; если нужны агрегаты — вычисляйте их в самом запросе через СУММА, КОЛИЧЕСТВО и группировки, а не суммированием в цикле.

Типичные ошибки
01
Обращение к полю без псевдонима в запросе — исключение «Поле не найдено» или непредсказуемое имя колонки
02
Чтение полей без проверки Пустой() или Следующий() — ошибка на данных, где запрос ничего не вернул
03
Повторный обход той же выборки — цикл молча не выполняется, данные «теряются»
04
Выгрузка огромного результата в таблицу значений — перерасход памяти вместо потокового обхода выборкой
05
Неверный индекс при ВыполнитьПакет() из-за промежуточных пакетов УНИЧТОЖИТЬ — обращение не к тому результату

FAQ

Как получить одно значение из запроса без цикла?

Выполните запрос, получите выборку и один раз вызовите Следующий(): если он вернул Истина, читайте нужное поле. Например: Если Выборка.Следующий() Тогда Цена = Выборка.Цена; КонецЕсли;. Для скалярных значений убедитесь, что запрос возвращает ровно одну строку — при необходимости добавьте ПЕРВЫЕ 1.

Чем отличается Выполнить() от ВыполнитьПакет()?

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

Как обратиться к полю, если в запросе есть итоги?

Получите выборку с параметром ОбходРезультатаЗапроса.ПоГруппировкам. Строки верхнего уровня содержат значения полей группировок и итоговые поля, а детальные записи внутри каждой группы доступны через вложенный вызов Выбрать() у текущей строки выборки.

Почему обращение Выборка.МоёПоле вызывает ошибку «Поле не найдено»?

Имя колонки результата определяется псевдонимом в секции ВЫБРАТЬ, а не именем реквизита в базе. Проверьте, что в тексте запроса поле объявлено как «ВЫБРАТЬ ... КАК МоёПоле», и что обращение написано с точно таким же именем без опечаток.

Можно ли обратиться к результату запроса по индексу строки без выгрузки?

Нет. Выборка поддерживает только последовательный обход через Следующий() и не имеет произвольного доступа по номеру строки. Если нужен доступ по индексу, выгрузите результат методом Выгрузить() и обращайтесь к строкам таблицы значений: ТаблицаРезультат[Индекс].

Как узнать состав колонок результата, если запрос формируется динамически?

Используйте коллекцию РезультатЗапроса.Колонки: у каждого элемента есть свойства Имя и ТипЗначения. Перебрав коллекцию в цикле, можно построить универсальный обход, который читает поля по именам из самой коллекции и не зависит от конкретного текста запроса.

Итог

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

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