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

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

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

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

Параметры запроса в 1С — это именованные значения, которые подставляются в текст запроса вместо символов &ИмяПараметра. Они позволяют передавать в запрос отборы, границы периодов, ссылки на объекты и списки значений, не изменяя сам текст запроса. Это делает код безопаснее (исключается конкатенация строк с данными пользователя) и удобнее для сопровождения.

Для установки параметров используется метод УстановитьПараметр(ИмяПараметра, Значение) объекта Запрос. Параметры нужно установить до вызова Выполнить() или ВыполнитьПакет(), иначе платформа выдаст ошибку о незаданном параметре либо запрос вернёт пустой результат без явного сообщения — в зависимости от того, где параметр используется.

Ниже разобраны синтаксис, типы передаваемых значений, работа со списками и виртуальными таблицами, а также типичные ошибки, из-за которых запрос «молча» возвращает пустой результат.

Базовый синтаксис: объявление и установка параметра

В тексте запроса параметр обозначается амперсандом и именем без пробелов: &Контрагент, &НачалоПериода. Одно и то же имя можно использовать в тексте несколько раз — значение подставится везде, где встречается параметр.

Значение задаётся в коде модуля до выполнения запроса. Имена параметров в методе УстановитьПараметр указываются без амперсанда и нечувствительны к регистру.

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

| РеализацияТоваровУслуг.Контрагент = &Контрагент

| И РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода";

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

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));

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

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

Порядок установки параметров не важен — важно только, чтобы все они были заданы до выполнения. Если параметр объявлен в тексте, но не установлен, при вызове Выполнить() возникнет ошибка «Переменная не определена» с указанием имени параметра.

Какие типы значений можно передавать в параметр

Параметр принимает большинство типов, с которыми работает язык запросов: строки, числа, булево, даты, ссылки на объекты базы, перечисления, а также массивы и списки значений для условий с несколькими вариантами.

Особое значение — Неопределено. Передавать его в параметр, который сравнивается с полем через =, нельзя: сравнение с NULL в запросе всегда даёт ложь, и результат будет пустым без ошибки. Если значение может быть не заполнено, это нужно обрабатывать отдельным условием.

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

Для пустой ссылки (например, когда отбор по организации не задан и нужны все организации) передают Неопределено в сочетании с конструкцией ГДЕ (&Организация = НЕОПРЕДЕЛЕНО ИЛИ Таблица.Организация = &Организация). Это стандартный приём «отключаемого» отбора.

Передача массивов и списков для условий «В» и «В ИЕРАРХИИ»

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

МассивСкладов = Новый Массив;

МассивСкладов.Добавить(СкладОсновной);

МассивСкладов.Добавить(СкладРозничный);

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

// В тексте запроса:

// ГДЕ Остатки.Склад В (&Склады)

Для иерархических справочников применяется В ИЕРАРХИИ (&Группа). В параметр можно передать как одну группу, так и массив групп — платформа развернёт иерархию для каждой. Это избавляет от необходимости вручную собирать все подчинённые элементы.

Ограничение: элементы массива должны быть сравнимого с полем типа. Если в массив со ссылками на справочник «Номенклатура» попадёт строка или ссылка другого типа, сравнение для такого элемента просто не сработает, а в отдельных случаях запрос завершится ошибкой несоответствия типов.

Типичные ошибки
01
Передача Неопределено в условие с "=" — запрос возвращает пустой результат без ошибки; используйте ЯВЛЯЕТСЯ NULL или отключаемый отбор
02
Дата без КонецДня() в правой границе — документы последнего дня после 00:00 выпадают из выборки
03
Передача массива в условие "=" вместо "В (&Параметр)" — сравнение не срабатывает
04
Установка параметра после Выполнить() — запрос выполняется со старым или незаданным значением

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

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

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

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

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

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

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

Параметры в консоли запросов и динамических списках

При отладке запроса в консоли запросов (типовой или внешней обработкой) каждый параметр из текста появляется на отдельной вкладке «Параметры». Там нужно вручную указать тип и значение — это эквивалент вызова УстановитьПараметр в коде. Консоль удобна для проверки текста запроса перед переносом в модуль.

Для динамических списков форм параметры устанавливаются иначе — через коллекцию Параметры компоновки данных: Список.Параметры.УстановитьЗначениеПараметра("НачалоПериода", ДатаНачала). Если параметр динамического списка не установлен, список на форме может оказаться пустым, а в журнале ошибок появится сообщение о незаданном параметре.

В отчётах на СКД параметры задаются в настройках схемы компоновки, а в коде — через КомпоновщикНастроек.Настройки.ПараметрыДанных. Имена параметров в СКД должны совпадать с именами в тексте запроса набора данных.

Маршрут решения

Как выбрать способ установки

Запрос выполняется в коде модуляИспользуйте Запрос.УстановитьПараметр() до вызова Выполнить()
Нужно отладить текст запросаПеренесите текст в консоль запросов и задайте параметры на вкладке «Параметры»
Отбор в динамическом списке формыУстановите значение через Список.Параметры.УстановитьЗначениеПараметра()
Параметр отчёта на СКДЗадайте его в настройках компоновщика или через ПараметрыДанных в коде

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

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

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

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

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

Коллекция Запрос.Параметры в отладчике
Норма

Все параметры из текста запроса присутствуют и имеют ожидаемые значения

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

Параметра нет или значение Неопределено там, где ожидалась ссылка

Границы периода
Норма

НачалоПериода = начало дня, КонецПериода = конец дня

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

КонецПериода содержит время 00:00:00 — теряются документы последнего дня

Тип значения параметра
Норма

Тип совпадает с типом поля в условии

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

Строка вместо ссылки, дата вместо момента времени

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

Ограничения и безопасная работа с параметрами

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

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

Итог

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

Параметры объявляются в тексте как &Имя, устанавливаются методом УстановитьПараметр до Выполнить(). Массивы передаются одним параметром для условий В и В ИЕРАРХИИ. Пустой результат чаще всего означает Неопределено в параметре, неверный тип или дату без КонецДня(). Динамические списки и СКД используют собственные механизмы установки параметров.

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

Что делать, если появляется ошибка «Переменная не определена» с именем параметра?

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

Можно ли передать в параметр таблицу значений?

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

Как передать в параметр «все значения», то есть отключить отбор?

Используйте отключаемое условие: ГДЕ (&Параметр = НЕОПРЕДЕЛЕНО ИЛИ Поле = &Параметр). Когда отбор не нужен, передавайте Неопределено, когда нужен — конкретное значение. Альтернатива для СКД — флаг использования параметра в настройках.

Почему запрос с параметром-датой не находит документы за последний день периода?

Дата документа содержит время, а переданная граница — полночь последнего дня. Условие Дата <= &КонецПериода отсекает все документы позже 00:00:00. Передавайте КонецДня(ДатаОкончания) или момент времени.

Работает ли УстановитьПараметр для запросов в пакетном режиме?

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

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

Платформа не формирует текст с подставленными значениями напрямую. Значения смотрят в отладчике в коллекции Запрос.Параметры. Для анализа реального SQL можно включить технологический журнал с событием DBMSSQL, но для большинства задач достаточно отладчика и консоли запросов.