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

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

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

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

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

Работа с запросами делится на три практических сценария: написание и отладка текста запроса в консоли, выполнение запроса программно из встроенного языка и использование запроса как источника данных в СКД или отчёте. Каждый сценарий имеет свои инструменты и типичные ошибки, которые разбираются ниже.

Как устроен язык запросов 1С

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

К реквизитам объекта обращаются через точку от имени таблицы или её псевдонима. Псевдонимы задаются ключевым словом КАК и делают текст читаемым. Условия отбора пишутся в секции ГДЕ, сортировка — в УПОРЯДОЧИТЬ ПО, группировка с агрегатными функциями — в СГРУППИРОВАТЬ ПО.

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

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

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

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

Порядок выполнения запроса из кода
  1. 1
    Создайте объект: Запрос = Новый Запрос;
  2. 2
    Присвойте текст: Запрос.Текст = "ВЫБРАТЬ ...";
  3. 3
    Установите все параметры: Запрос.УстановитьПараметр("Дата", ТекущаяДатаСеанса());
  4. 4
    Выполните: Результат = Запрос.Выполнить();
  5. 5
    Получите выборку: Выборка = Результат.Выбрать(); и обойдите её в цикле Пока Выборка.Следующий() Цикл
  6. 6
    Либо выгрузите в таблицу значений: Таб = Результат.Выгрузить();

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

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Остатки.Номенклатура КАК Номенклатура,
|	Остатки.КоличествоОстаток КАК Остаток
|ИЗ
|	РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата, Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Дата", КонецДня(ДатаОтчета));
Запрос.УстановитьПараметр("Склад", Склад);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
	Сообщить(Строка(Выборка.Номенклатура) + ": " + Выборка.Остаток);
КонецЦикла;

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

Параметры запроса: зачем нужны и как передавать

Параметры в тексте запроса обозначаются амперсандом: &Дата, &Склад, &СписокНоменклатуры. Каждый параметр, встречающийся в тексте, обязан быть установлен вызовом УстановитьПараметр() — иначе выполнение завершится ошибкой «Переменная не определена». Обратное тоже верно: лишние установленные параметры, которых нет в тексте, платформа игнорирует.

Параметры предпочтительнее конкатенации значений прямо в текст запроса по двум причинам. Во-первых, типизация сохраняется автоматически: дата передаётся как дата, ссылка — как ссылка, и сравнение работает корректно. Во-вторых, подстановка строк в текст — источник ошибок с кавычками и форматами дат, а при работе с СУБД — ещё и потенциальная уязвимость.

Для отбора по списку значений параметру передают массив или список значений, а в условии используют оператор В: ГДЕ Номенклатура В (&СписокНоменклатуры). Для сравнения по шаблону строки применяют ПОДОБНО с символами % и _, при этом специальные символы в самом параметре нужно экранировать.

Типичные ошибки с параметрами
01
Параметр объявлен в тексте, но не установлен в коде — запрос падает с ошибкой при выполнении
02
В параметр виртуальной таблицы Остатки передана дата без времени — остатки посчитаны на начало дня, а не на конец; используйте КонецДня() или границу
03
Подстановка даты конкатенацией в текст — формат строки не совпадает с ожиданием платформы, запрос не выполняется
04
Передача пустого массива в условие В — результат всегда пустой, что выглядит как «запрос не работает»

Виртуальные таблицы регистров

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

Ключевое правило производительности: отбор по измерениям задавайте в параметрах виртуальной таблицы, а не в секции ГДЕ. Условие Остатки(&Дата, Склад = &Склад) заставит платформу сразу вычислить остатки только по нужному складу. То же условие в ГДЕ сначала вычислит остатки по всем складам, а потом отфильтрует — на больших базах разница во времени выполнения кратная.

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

Консоль запросов: как отлаживать текст без изменения кода

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

Консоль запросов входит в типовую подсистему «Инструменты разработчика» во многих конфигурациях на БСП, а также распространяется как отдельная обработка. В типовых решениях её часто можно найти в разделе администрирования или через «Все функции». Для работы консоли пользователю обычно требуются права на чтение соответствующих данных и возможность запуска внешних обработок.

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

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

Запросы в СКД, динамических списках и пакетные запросы

В системе компоновки данных запрос — это источник данных набора. Текст пишется тем же языком, но СКД добавляет свои расширения: секцию ХАРАКТЕРИСТИКИ, язык выражений для вычисляемых полей и параметры, которые пользователь настраивает в отчёте. Отладку запроса для СКД удобно начинать в консоли, а затем переносить в набор данных, помня, что отборы пользователя СКД добавит сама.

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

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

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

Производительность и безопасные границы

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

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

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

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

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

Совпадает с ожиданием по контрольному примеру (например, числу документов за день)

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

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

Суммы и остатки
Норма

Сходятся со стандартным отчётом конфигурации за тот же период

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

Расхождения — проверьте границу периода, отборы виртуальной таблицы и вид движения

Время выполнения
Норма

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

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

Минуты ожидания — перенесите отборы в параметры виртуальных таблиц, уберите запросы из циклов

FAQ: частые вопросы о запросах в 1С

Чем запрос отличается от обхода данных объектными методами?

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

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

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

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

Передайте в параметр виртуальной таблицы объект Граница: Новый Граница(МоментВремени, ВидГраницы.Включая) — тогда остатки будут рассчитаны на конкретный документ. Если достаточно точности до даты, используйте КонецДня(Дата), иначе остатки посчитаются на начало дня.

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

Нет, объект Запрос доступен только на сервере. В управляемых формах запрос выполняют в серверной процедуре (с директивой &НаСервере), а результат возвращают на клиент в виде таблицы значений, массива структур или через реквизит формы типа ДинамическийСписок.

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

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

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

Создайте ТабличныйДокумент, получите макет с областями шапки и строки, затем в цикле обхода выборки заполняйте параметры области и выводите её методом Вывести(). Для отчётов сложнее простой таблицы удобнее использовать СКД — она сама строит макет и оформление.

Итог

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

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