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

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

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

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

Обработка запроса в 1С — это последовательность действий: создать объект «Запрос», задать текст на встроенном языке запросов, передать параметры, выполнить запрос и обработать полученный результат. Каждый этап имеет свои особенности, и ошибка на любом из них приводит либо к падению кода с исключением, либо к тихому получению неверных данных.

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

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

Создание объекта запроса и написание текста

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

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

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Товар,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления";

Обращайте внимание на псевдонимы полей (конструкция КАК): именно по ним вы будете обращаться к колонкам результата в коде. Если псевдоним не задан, платформа сформирует имя автоматически, и оно может не совпасть с вашими ожиданиями — например, для полей через точку.

Передача параметров и фильтрация данных

Параметры объявляются в тексте запроса символом амперсанда: &Склад, &Период. Значения устанавливаются методом УстановитьПараметр("ИмяПараметра", Значение) до вызова метода Выполнить(). Если параметр объявлен в тексте, но значение ему не присвоено, запрос упадёт с ошибкой при выполнении.

Никогда не подставляйте значения в текст запроса конкатенацией строк. Помимо риска синтаксических ошибок с кавычками и датами, это мешает СУБД повторно использовать скомпилированный план запроса — каждый новый текст компилируется заново, что заметно замедляет работу при массовых вызовах.

Для отбора по списку значений передайте в параметр массив или список значений и используйте оператор В (&СписокТоваров). Для отбора по таблице с несколькими колонками передайте таблицу значений и поместите её во временную таблицу — так можно соединять её с другими таблицами по нескольким полям.

Выполнение запроса и способы обработки результата

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

Обход через выборку

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

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

Метод Выгрузить() загружает весь результат в память как таблицу значений. Её удобно сортировать, сворачивать, искать строки через Найти() и НайтиСтроки(). Для небольших выборок это проще и быстрее в разработке, но при сотнях тысяч строк расход памяти станет проблемой — особенно на сервере с несколькими сеансами.

Сравнение вариантов

Выбрать() — выборка

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

Выгрузить() — таблица значений

Удобна для сортировки, поиска и многократного обхода; ограничение — весь результат хранится в памяти.

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

Подходит для иерархических данных с группировками; требует аккуратной работы со строками дерева.

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

Пакетный запрос содержит несколько операторов, разделённых точкой с запятой. Промежуточные результаты помещаются во временные таблицы конструкцией ПОМЕСТИТЬ ИмяТаблицы, а финальный оператор ВЫБРАТЬ возвращает результат. Это основной приём для сложной выборки: сначала отфильтровать данные во временную таблицу, потом соединить её с остальными.

Метод ВыполнитьПакет() возвращает массив результатов — по одному на каждый оператор, возвращающий данные. Операторы с ПОМЕСТИТЬ в этот массив не попадают, поэтому индексы в массиве соответствуют только «выводящим» запросам пакета.

Временные таблицы живут внутри менеджера временных таблиц. Если нужно использовать одни и те же временные таблицы в нескольких объектах запроса, создайте Новый МенеджерВременныхТаблиц и присвойте его свойству МенеджерВременныхТаблиц каждого запроса. Иначе второй запрос не увидит таблицы первого.

bsl
Запрос.Текст =
"ВЫБРАТЬ Товары.Ссылка КАК Товар
|ПОМЕСТИТЬ ВТ_Отбор
|ИЗ Справочник.Номенклатура КАК Товары
|ГДЕ Товары.Родитель = &Группа
|;
|ВЫБРАТЬ Остатки.Товар, Остатки.КоличествоОстаток
|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&Период,
| Товар В (ВЫБРАТЬ Товар ИЗ ВТ_Отбор)) КАК Остатки";

Проверка результата и обработка пустых выборок

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

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

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

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

Наличие строк в результате
Норма

РезультатЗапроса.Пустой() = Ложь, выборка открывается

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

Пустой() = Истина — проверьте параметры отбора и условия соединений

Состав колонок
Норма

Колонки доступны по псевдонимам из текста запроса

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

Ошибка «Поле не найдено» — псевдоним в коде не совпадает с псевдонимом в запросе

Типы значений в колонках
Норма

Значения ожидаемых типов, NULL обработаны

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

Необработанные NULL из левых соединений ломают сравнения и арифметику

Отдельно следите за значениями NULL: они появляются при левых соединениях, когда в присоединяемой таблице нет подходящей строки. Сравнение с NULL всегда даёт Ложь, арифметика с NULL даёт NULL. Используйте функцию ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) прямо в тексте запроса.

Типичные ошибки при обработке запросов

Большинство проблем с запросами сводится к нескольким повторяющимся сценариям. Их знание сокращает отладку с часов до минут, потому что симптомы почти всегда одинаковые.

Типичные ошибки
01
Конкатенация значений в текст запроса — синтаксические ошибки на кавычках и датах, перекомпиляция плана на каждом вызове.
02
Запрос в цикле — тысячи обращений к СУБД вместо одного запроса с соединением; типичная причина «тормозов» проведения документов.
03
Отсутствие ЕСТЬNULL при левом соединении — NULL в итоговых суммах и неожиданно пустые отборы.
04
Не установлен параметр виртуальной таблицы (период остатков) — запрос считает остатки на момент без отсечки и работает медленнее.
05
Обращение к колонке по имени поля вместо псевдонима — ошибка «Поле не найдено» при обходе выборки.
06
Выгрузка огромного результата в таблицу значений на сервере — рост памяти рабочего процесса и замедление всех сеансов.

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

Отладка и оптимизация запроса

Первый инструмент отладки — консоль запросов: внешняя обработка или встроенная консоль в режиме предприятия (в типовых конфигурациях на БСП — «Инструменты разработчика»). Скопируйте текст запроса, подставьте реальные параметры и проверьте результат отдельно от кода. Так вы быстро отделите ошибку в запросе от ошибки в его обработке.

Для поиска фактических параметров в момент выполнения поставьте точку останова перед Выполнить() и посмотрите значения в табло. Если запрос работает медленно, проверьте: используются ли параметры виртуальных таблиц, нет ли соединений по неиндексированным полям, не выбираются ли лишние поля «про запас».

Порядок действий
  1. 1
    Сформулируйте, какие данные нужны, и набросайте текст в консоли запросов.
  2. 2
    Создайте объект Запрос и присвойте текст свойству Текст.
  3. 3
    Установите все параметры через УстановитьПараметр().
  4. 4
    Выполните запрос и проверьте РезультатЗапроса.Пустой().
  5. 5
    Обработайте результат выборкой или выгрузкой в таблицу значений.
  6. 6
    Проверьте обработку NULL и поведение при пустом результате.
Держите текст запроса рядом с кодом его обработки и именуйте псевдонимы так же, как переменные в коде. Когда запрос и обход написаны в единой терминологии, ошибки «поле не найдено» исчезают почти полностью, а чтение чужого кода ускоряется в разы.
ПЗ
Практическое замечание
Итог

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

Обработка запроса — это цепочка: текст, параметры, выполнение, проверка на пустоту, обход результата. Используйте параметры вместо конкатенации, выбирайте между выборкой и таблицей значений по объёму данных, обрабатывайте NULL и не выполняйте запросы в цикле.

Частые вопросы

Чем Выбрать() отличается от Выгрузить() и что быстрее?

Выбрать() возвращает выборку для последовательного чтения строка за строкой — это экономит память. Выгрузить() загружает весь результат в таблицу значений, что удобнее для поиска и сортировки, но требует памяти под все строки. На малых объёмах разница незаметна, на больших выборка предпочтительнее.

Почему запрос в консоли работает, а в коде падает с ошибкой?

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

Как передать в запрос список значений для отбора?

Соберите значения в массив или список значений, передайте его через УстановитьПараметр() и используйте в тексте оператор В (&Параметр). Пустой список в таком условии не вернёт ни одной строки — при необходимости добавьте проверку на пустоту списка до выполнения запроса.

Можно ли изменить данные в базе через запрос?

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

Что делать, если запрос выполняется слишком долго?

Проверьте параметры виртуальных таблиц — остатки и обороты без отсечки по периоду и измерениям считаются по всем данным. Уберите лишние поля и соединения, убедитесь, что условия соединений идут по индексированным полям, и рассмотрите вынос отборов во временную таблицу. Запрос в цикле замените одним запросом с соединением.

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

Обрабатывайте NULL на уровне текста запроса функцией ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) — это заменит NULL на указанное значение ещё до передачи в код. Если NULL уже попал в выборку, проверяйте его через Значение = Неопределено не сработает — используйте сравнение с NULL недоступно в языке, поэтому правильная точка обработки именно запрос.