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

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

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

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

Запросы в 1С — основной способ получения данных из информационной базы: через них строятся отчёты, заполняются табличные части документов, проверяются остатки и обороты. Язык запросов 1С внешне похож на SQL, но работает не с таблицами базы данных напрямую, а с объектами метаданных: справочниками, документами, регистрами накопления и сведений.

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

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

Структура простого запроса

Минимальный запрос состоит из секции ВЫБРАТЬ с перечнем полей и секции ИЗ с указанием таблицы. Таблицей выступает объект метаданных: например, Справочник.Номенклатура или Документ.РеализацияТоваровУслуг. Для виртуальных таблиц регистров указывается полное имя вида РегистрНакопления.ТоварыНаСкладах.Остатки.

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления";

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

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

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

Сообщить(Выборка.Товар);

КонецЦикла;

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

Как собрать текст запроса конструктором

Конструктор запроса избавляет от необходимости помнить имена таблиц и полей. Откройте его из контекстного меню в модуле: правой кнопкой по тексту модуля → «Конструктор запроса». Если курсор стоит внутри существующего текста запроса, конструктор загрузит его для редактирования.

В левой части конструктора выберите базу данных (объекты метаданных), перенесите нужные таблицы в среднюю колонку, затем выберите поля. На закладках «Связи», «Условия», «Группировка», «Итоги» настраиваются соединения, отборы и агрегация. После нажатия «ОК» конструктор сформирует корректный текст запроса автоматически.

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

Конструктор полезен и опытным разработчикам: он гарантирует правильность имён полей и синтаксиса соединений. Однако итоговый текст стоит читать и понимать — при оптимизации медленных запросов придётся править его вручную.

Параметры и отборы

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

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

"ВЫБРАТЬ

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

| Остатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки";

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

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

Обратите внимание: у виртуальных таблиц регистров параметры (период, условия) указываются в скобках сразу после имени таблицы. Отбор в параметрах виртуальной таблицы работает быстрее, чем тот же отбор в секции ГДЕ, потому что платформа сокращает объём вычисляемых данных ещё на этапе формирования виртуальной таблицы.

Соединения таблиц и объединения

Соединения позволяют получить данные из нескольких таблиц одним запросом. Чаще всего используется ЛЕВОЕ СОЕДИНЕНИЕ: из основной таблицы берутся все строки, а из присоединяемой — только совпавшие по условию. Например, список номенклатуры с остатками, где у части товаров остатка может не быть вовсе.

"ВЫБРАТЬ

| Товары.Ссылка КАК Товар,

| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток

|ИЗ

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

| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК Остатки

| ПО Товары.Ссылка = Остатки.Номенклатура"

Функция ЕСТЬNULL заменяет NULL на заданное значение — без неё в полях из присоединённой таблицы при отсутствии совпадений окажется NULL, что сломает сравнения и арифметику в дальнейшей обработке. ВНУТРЕННЕЕ СОЕДИНЕНИЕ оставляет только строки, где совпадение есть в обеих таблицах; ПРАВОЕ и ПОЛНОЕ используются реже.

Для склейки однотипных наборов данных (например, приход и расход из разных регистров) применяется ОБЪЕДИНИТЬ — с сохранением дублей, или ОБЪЕДИНИТЬ ВСЕ. Помните: ОБЪЕДИНИТЬ без ВСЕ дополнительно устраняет дубликаты, что требует сортировки и замедляет выполнение.

Группировки, итоги и сортировка

Агрегатные функции — СУММА, КОЛИЧЕСТВО, МАКСИМУМ, МИНИМУМ, СРЕДНЕЕ — применяются с секцией СГРУППИРОВАТЬ ПО. Все неагрегатные поля из списка выборки обязаны попасть в группировку, иначе запрос не выполнится. Для подсчёта уникальных значений используйте КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле).

Секция ИТОГИ ПО строит иерархические итоги: например, суммы по складу и общий итог. При обходе такой выборки используется ОбходРезультатаЗапроса.ПоГруппировкам, а уровень группировки определяется через ТипЗаписи(). Сортировка задаётся секцией УПОРЯДОЧИТЬ ПО с указанием направления ВОЗР или УБЫВ.

Для ограничения числа строк есть конструкция ВЫБРАТЬ ПЕРВЫЕ N — удобно для отборов «топ-10 товаров» или проверки наличия хотя бы одной записи (ПЕРВЫЕ 1 вместо подсчёта всех строк).

Обработка результата и временные таблицы

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

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

Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

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

"ВЫБРАТЬ

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

|ПОМЕСТИТЬ ВТ_Товары

|ИЗ

| Документ.РеализацияТоваровУслуг.Товары КАК Док

|ГДЕ

| Док.Ссылка = &Ссылка

|;

|ВЫБРАТЬ

| ВТ.Товар КАК Товар,

| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток

|ИЗ

| ВТ_Товары КАК ВТ

| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(, ) КАК Остатки

| ПО ВТ.Товар = Остатки.Номенклатура";

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

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

Количество строк в выборке
Норма

Совпадает с ожидаемым числом записей по отбору

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

Строк заметно больше — вероятно, ошибка в условии соединения

Значения числовых полей
Норма

Числа без NULL, итоги сходятся с отчётом в пользовательском режиме

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

Встречается NULL или суммы завышены из-за дублей

Скорость выполнения
Норма

Запрос выполняется за доли секунды на рабочем объёме данных

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

Заметная пауза даже на небольшой базе — проверьте отборы и индексы

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

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

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

Типичные ошибки
01
Запрос внутри цикла обхода — резкое падение производительности
02
Конкатенация значений в текст запроса вместо параметров — ошибки синтаксиса и риск некорректных данных
03
Отбор в ГДЕ вместо параметров виртуальной таблицы — лишний объём вычислений
04
Отсутствие ЕСТЬNULL при левом соединении — NULL в расчётах и сравнениях
05
ОБЪЕДИНИТЬ вместо ОБЪЕДИНИТЬ ВСЕ — лишняя сортировка и потеря нужных дублей или их неожиданное удаление

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

Итог

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

Запрос — это объект с текстом, параметрами и результатом. Пишите текст через конструктор, значения передавайте параметрами, отборы виртуальных таблиц задавайте в их параметрах, соединения сопровождайте ЕСТЬNULL, а сложную логику разбивайте на временные таблицы. Один хороший запрос всегда лучше множества запросов в цикле.

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

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

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

Как проверить, что запрос ничего не вернул?

У результата запроса есть свойство Пустой: Результат.Пустой(). Либо проверяйте вход в цикл выборки — если Следующий() сразу вернул Ложь, записей нет. Для таблицы значений проверяйте Количество() = 0.

Можно ли использовать запрос вне отчёта?

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

Что такое консоль запросов и зачем она нужна?

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

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

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

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

Чаще всего причина в объёме данных и отсутствии подходящих индексов по полям отбора и соединения. Проверьте, что отборы идут по индексированным полям (измерения регистров, реквизиты с признаком индексирования), а отборы виртуальных таблиц заданы в их параметрах, а не в секции ГДЕ.