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