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