Разработка и Конфигурация · 11 мин
Как передать параметры в запрос 1С
Как передать параметры в запрос 1С: метод УстановитьПараметр, даты, списки, таблицы значений, типичные ошибки и проверка результата.
Параметры в запросах 1С используются везде, где текст запроса содержит переменные условия: отбор по контрагенту, периоду, списку номенклатуры или таблице значений. Правильная передача параметров влияет не только на корректность результата, но и на производительность: запрос с параметрами кэшируется СУБД, а подстановка значений конкатенацией строк — нет и вдобавок открывает риск ошибок синтаксиса.
Все параметры в тексте запроса обозначаются символом амперсанда: &Период, &Контрагент, &СписокТоваров. Значения им присваиваются через метод УстановитьПараметр() объекта «Запрос» до вызова Выполнить() или ВыполнитьПакет(). Если параметр объявлен в тексте, но не установлен, платформа выдаст ошибку «Переменная не определена».
Материал разбирает базовый синтаксис, передачу дат и периодов, списков значений, таблиц значений как параметров, особенности виртуальных таблиц и типичные ошибки, из-за которых запрос возвращает пустой результат или падает с ошибкой.
Базовый синтаксис: УстановитьПараметр
Минимальный рабочий пример выглядит так: создаётся объект запроса, задаётся текст с параметром, параметр устанавливается, запрос выполняется.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Товар,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Родитель = &Группа";
Запрос.УстановитьПараметр("Группа", ВыбраннаяГруппа);
Результат = Запрос.Выполнить().Выгрузить();
Имя параметра в УстановитьПараметр() пишется без амперсанда и без учёта регистра. Порядок установки параметров относительно друг друга не важен — важно только, чтобы все они были заданы до выполнения. Один и тот же параметр можно использовать в тексте несколько раз, устанавливать его нужно один раз.
Повторный вызов УстановитьПараметр() с тем же именем перезаписывает значение. Это удобно в циклах: текст запроса остаётся неизменным, меняется только параметр, и СУБД может повторно использовать уже построенный план запроса.
Передача дат и периодов
Даты передаются как значения типа «Дата», а не как строки. Частая ошибка — сформировать строку вида «20260101» и передать её в параметр: сравнение даты со строкой либо даст ошибку, либо вернёт пустой результат в зависимости от СУБД.
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));
Для отбора документов за период используйте границы МЕЖДУ &НачалоПериода И &КонецПериода или сравнения >= и <=. Помните, что у даты в 1С есть время: если передать дату окончания без времени, она будет равна началу дня, и документы за сам день окончания не попадут в выборку. Поэтому применяйте КонецДня().
При работе с виртуальными таблицами регистров (Остатки, Обороты) период задаётся в параметрах виртуальной таблицы, а не в секции ГДЕ — об этом подробнее ниже.
Передача списков и массивов
Для условий вида «номенклатура входит в список» параметру передаётся массив, список значений или таблица значений, а в тексте используется оператор В:
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Товар
|ИЗ
| Справочник.Номенклатура КАК Товары
|ГДЕ
| Товары.Ссылка В (&СписокТоваров)";
Запрос.УстановитьПараметр("СписокТоваров", МассивТоваров);
Пустой массив — источник коварной ошибки: условие В (&Список) с пустым списком не вернёт ни одной строки, и это логически корректно, но часто неожиданно для разработчика. Если пустой список должен означать «без отбора», добавьте конструкцию с проверкой: ГДЕ (&СписокПуст ИЛИ Товар В (&Список)) и передайте булев параметр, либо формируйте текст запроса динамически.
Оператор В ИЕРАРХИИ работает аналогично: передайте массив групп справочника, и в выборку попадут элементы всех вложенных уровней.
Передача таблицы значений как параметра
Таблица значений передаётся в запрос для создания временной таблицы — это стандартный способ отфильтровать данные по произвольному набору пар «номенклатура + характеристика», по списку документов с дополнительными колонками и т.п. Параметр помещается в секцию ПОМЕСТИТЬ:
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.Товар КАК Товар,
| ТЗ.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТЗ КАК ТЗ
|;
|ВЫБРАТЬ
| ВТ.Товар КАК Товар,
| Остатки.КоличествоОстаток КАК Остаток
|ИЗ
| ВТ_Товары КАК ВТ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
| ПО ВТ.Товар = Остатки.Номенклатура";
Запрос.УстановитьПараметр("ТЗ", ТаблицаТоваров);
Требования к таблице значений: колонки должны быть типизированы, причём типы должны совпадать с типами полей, с которыми они сравниваются. Если колонка «Товар» имеет составной тип или не заполнен тип вовсе, соединение может вернуть пустой результат. Для временных таблиц в пакетном запросе потребуется менеджер временных таблиц при передаче между запросами, либо пакет внутри одного объекта запроса, как в примере выше.
Параметры виртуальных таблиц регистров
Виртуальные таблицы регистров (Остатки, Обороты, СрезПоследних, СрезПервых) принимают параметры в круглых скобках после имени таблицы. Это принципиально отличается от секции ГДЕ: параметры виртуальной таблицы применяются до выборки данных и напрямую влияют на производительность.
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Товар,
| Остатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Период", КонецДня(ДатаОстатков));
Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);
Для «СрезПоследних» и «СрезПервых» первый параметр — период, второй — условие отбора по измерениям. Если период не нужен (актуальный срез), скобки оставляют пустыми: СрезПоследних(, Номенклатура = &Товар). Отбор в скобках виртуальной таблицы почти всегда эффективнее аналогичного условия в ГДЕ, потому что СУБД читает меньше данных.
Конструкция «В (&Параметр)» против соединения с временной таблицей
Когда нужно отфильтровать по набору значений, есть два подхода: передать массив в оператор В или поместить таблицу значений во временную таблицу и соединиться с ней. Выбор зависит от объёма и структуры данных.
| Критерий | Массив в В (&Параметр) | Временная таблица из ТЗ |
|---|---|---|
| Размер набора | Десятки–сотни значений | Тысячи строк и больше |
| Структура | Одно значение (ссылка, код) | Несколько колонок, составной ключ |
| Дополнительные данные | Не передаются | Можно тащить колонки (количество, цена) |
| Подготовка | Минимальная | Нужна типизированная таблица значений |
Для составных условий (товар + склад + характеристика) массив не подходит в принципе — только временная таблица с соединением по всем полям. Для простого отбора по десятку контрагентов массив проще и читаемее.
Сравнение вариантов
Подходит для небольших списков однотипных значений. Ограничение: одно поле сравнения, при большом объёме ухудшает план запроса
Подходит для больших наборов и составных ключей, позволяет передать дополнительные колонки. Ограничение: требует типизации колонок и больше кода
Самый быстрый вариант для регистров: фильтрация до чтения данных. Ограничение: работает только с измерениями и периодом виртуальной таблицы
Проверка результата и отладка параметров
Если запрос с параметрами возвращает пустой результат, проверяйте в первую очередь типы и значения параметров. Выведите их в отладчике: ТипЗнч(Значение) и само значение. Убедитесь, что ссылка относится к тому же типу, что и поле сравнения, — ссылка на «Номенклатуру» никогда не равна ссылке на «Партнёра», даже если наименования совпадают.
Для отладки удобно временно убрать условие и посмотреть, есть ли вообще данные в таблице, затем возвращать условия по одному. Так локализуется параметр, который «режет» выборку. Полезно также выполнить запрос в консоли запросов с теми же значениями параметров — это отделяет проблему данных от проблемы кода.
Как проверить результат
ТипЗнч() даёт тот же тип, что у поля сравнения (например, СправочникСсылка.Номенклатура)
Строка вместо даты, неопределено, ссылка другого справочника
Конец периода содержит время 23:59:59 или используется КонецДня()
Время 00:00:00 — документы последнего дня не попадают
Массив заполнен, элементы нужного типа
Пустой массив или элементы-строки вместо ссылок
Запрос выполняется без исключений, Выборка.Следующий() находит строки
Ошибка «Переменная не определена» — параметр не установлен
Частые вопросы
Можно ли передать параметр прямо в строке текста запроса через конкатенацию?
Технически можно, но делать так не стоит. Подстановка строк ломает кэширование плана запроса на СУБД, создаёт риск синтаксических ошибок на спецсимволах и делает код уязвимым при передаче пользовательского ввода. Используйте УстановитьПараметр для всех значений.
Как передать в запрос значение NULL?
Передайте значение Неопределено — платформа преобразует его в NULL. В тексте запроса проверяйте через «ЕСТЬ NULL» или сравнение «= &Параметр» в зависимости от логики. Помните, что сравнение с NULL через равенство не срабатывает: используйте конструкцию «Поле ЕСТЬ NULL».
Можно ли использовать один параметр в нескольких местах запроса?
Да. Параметр устанавливается один раз и может встречаться в тексте сколько угодно раз — в разных пакетах, подзапросах и условиях. Это удобно для периода, который используется и в виртуальной таблице, и в итоговом отборе.
Почему запрос с параметром-таблицей значений возвращает пустой результат?
Чаще всего причина в несовпадении типов колонок таблицы значений и полей базы. Проверьте, что колонка типизирована нужным типом ссылки, а не составным типом или строкой. Вторая причина — пустая таблица значений: соединение с пустой временной таблицей закономерно не даст строк.
Как передать параметр в динамический список, а не в объект Запрос?
У динамического списка параметры устанавливаются через коллекцию Параметры: ДинамическийСписок.Параметры.УстановитьЗначениеПараметра("Период", Дата). В тексте произвольного запроса динамического списка параметр обозначается тем же амперсандом.
Что важно запомнить
Все значения передаются через УстановитьПараметр до выполнения запроса, в тексте — с амперсандом. Даты передавайте типом Дата с правильными границами дня, списки — массивом в оператор В, большие наборы и составные ключи — таблицей значений во временную таблицу. Отборы по регистрам задавайте в параметрах виртуальных таблиц, а при пустом результате первым делом проверяйте типы параметров.