Работа с реквизитами форм в 1С:Предприятие — одна из самых востребованных задач при разработке отчетов, обработок и управляемых форм. Часто требуется передать значения полей формы в SQL-запрос, чтобы динамически фильтровать данные, формировать отчеты по текущим параметрам или интегрировать логику интерфейса с базой. Однако новичков этот процесс ставит в тупик: как правильно «достать» значение реквизита из формы и использовать его в тексте запроса?

В этой статье мы разберем три основных способа передачи реквизитов формы в запрос: через параметры запроса, временные таблицы и программное формирование текста запроса. Особое внимание уделим типовым ошибкам (например, когда запрос «не видит» передаваемые значения) и оптимизации производительности. Материал актуален для платформы 1С:Предприятие 8.3 (все актуальные релизы), включая управляемые и обычные формы.

Почему нельзя просто подставить значение реквизита в текст запроса?

Многие разработчики пытаются «в лоб» вставить значение реквизита формы прямо в строку запроса, например:

Запрос.Текст = "ВЫБРАТЬ * ИЗ Справочник.Номенклатура ГДЕ Наименование = """ + ЭлементыФормы.ПолеНаименования.Значение + """";

Такой подход чреват SQL-инъекциями и ошибками синтаксиса, особенно если значение реквизита содержит кавычки, спецсимволы или NULL. Кроме того, платформа обрабатывает запросы оптимизированно: при повторном выполнении идентичного запроса с другими параметрами используется кэш. Если же текст запроса каждый раз формируется заново — кэширование не работает, что тормозит систему.

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

📊 Какой способ передачи реквизитов в запрос вы используете чаще?
Через параметры запроса
Формирую текст запроса динамически
Использую временные таблицы
Другой вариант

Способ 1: Передача реквизитов через параметры запроса

Самый безопасный и рекомендуемый метод — использование параметров запроса. Он автоматически экранирует спецсимволы и позволяет платформе кэшировать план выполнения. Синтаксис:

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

| Номенклатура.Наименование ПОДОБНО &Наименование

| И Номенклатура.ПометкаУдаления = ЛОЖЬ";

Запрос.УстановитьПараметр("Наименование", "%" + ЭлементыФормы.ПолеПоиска.Значение + "%");

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

Ключевые моменты:

  • 🔹 Параметры обозначаются символом & (например, &ДатаНачала).
  • 🔹 Метод УстановитьПараметр() связывает имя параметра с реальным значением.
  • 🔹 Для строковых параметров можно использовать ПОДОБНО с подстановочными символами (%, _).
  • 🔹 Параметры типизированы: если передать число в строковый параметр, возникнет ошибка.
⚠️ Внимание: Если реквизит формы имеет тип Дата, убедитесь, что передаёте его без времени (используйте НачалоДня() или КонецДня() при необходимости). Например:
Запрос.УстановитьПараметр("ДатаДок", НачалоДня(ЭлементыФормы.ПолеДаты.Значение));

Убедиться, что имя параметра в запросе и в коде совпадают|Проверить соответствие типов (число/строка/дата)|Для строковых параметров экранировать кавычки или использовать ПОДОБНО|Обработать NULL-значения (если реквизит может быть пустым)-->

Способ 2: Использование временных таблиц для сложных данных

Если нужно передать в запрос не одно значение, а массив данных (например, список выбранных строк в табличной части формы), удобно использовать временные таблицы. Этот метод подходит для:

  • 📋 Фильтрации по нескольким значениям (например, список контрагентов из формы).
  • 📊 Передачи данных из табличных частей или динамических списков.
  • 🔄 Обработки промежуточных результатов между несколькими запросами.

Пример: передаём список выбранных номенклатурных позиций из табличной части формы в запрос для получения остатков:

// 1. Создаём временную таблицу

ВременнаяТаблица = Новый ТаблицаЗначений;

ВременнаяТаблица.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

// 2. Заполняем данными из формы

Для Каждого Строка Из ЭлементыФормы.ТабличнаяЧастьНоменклатуры.ВыбранныеСтроки Цикл

НоваяСтрока = ВременнаяТаблица.Добавить();

НоваяСтрока.Ссылка = Строка.Номенклатура;

КонецЦикла;

// 3. Передаём во временную таблицу запроса

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

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

"ВЫБРАТЬ

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

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

|ИЗ

| РегистрНакопления.ОстаткиНоменклатуры КАК ОстаткиНоменклатуры

|ГДЕ

| ОстаткиНоменклатуры.Номенклатура В (&СписокНоменклатуры)";

Запрос.УстановитьВременнуюТаблицу("СписокНоменклатуры", ВременнаяТаблица);

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

Тип данных формы Способ передачи Пример кода
Одиночное поле (строка, число, дата) Параметр запроса УстановитьПараметр("Имя", Значение)
Табличная часть (список значений) Временная таблица УстановитьВременнуюТаблицу("Имя", ТаблицаЗначений)
Динамический список Временная таблица или массив параметров УстановитьПараметр("Массив", МассивЗначений)
Ссылка на объект (справочник, документ) Параметр с типом Ссылка УстановитьПараметр("Ссылка", Объект.Ссылка)
💡

Если временная таблица содержит много строк (тысячи записей), разбейте её на части по 1000–2000 строк и выполните несколько запросов. Это ускорит обработку и избежит ошибок переполнения.

Способ 3: Динамическое формирование текста запроса

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

ТекстЗапроса = "ВЫБРАТЬ |";

Если ЭлементыФормы.ФлажокПоказатьАрхив.Значение Тогда

ТекстЗапроса = ТекстЗапроса + " Номенклатура.ПометкаУдаления = ЛОЖЬ ИЛИ Номенклатура.ПометкаУдаления = ИСТИНА |";

Иначе

ТекстЗапроса = ТекстЗапроса + " Номенклатура.ПометкаУдаления = ЛОЖЬ |";

КонецЕсли;

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

"ИЗ

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

|ГДЕ

| Номенклатура.Наименование ПОДОБНО &Наименование";

Запрос = Новый Запрос(ТекстЗапроса);

Запрос.УстановитьПараметр("Наименование", "%" + ЭлементыФормы.ПолеПоиска.Значение + "%");

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

Когда оправдан этот подход:

  • 🛠 Динамические фильтры: когда набор условий ГДЕ зависит от флажков или выпадающих списков формы.
  • 📊 Изменяемая структура выборки: например, пользователь выбирает, какие колонки показать в отчёте.
  • 🔗 Сложная логика соединений: когда таблицы в запросе соединяются по разным правилам в зависимости от параметров.
⚠️ Внимание: При динамическом формировании текста запроса всегда экранируйте значения реквизитов с помощью функции СтрЗначениеВSQLСтроку(), чтобы избежать SQL-инъекций:
ЗначениеДляЗапроса = СтрЗначениеВSQLСтроку(ЭлементыФормы.ПолеКомментария.Значение);
Что будет, если не экранировать значения в динамическом запросе?

Если значение реквизита содержит символы вроде кавычек (') или точки с запятой (;), это может привести к синтаксической ошибке или даже выполнению произвольного SQL-кода (SQL-инъекция). Например, если пользователь введёт в поле поиска строку "; УДАЛИТЬ ИЗ Справочник.Номенклатура ГДЕ 1=1;, неэкранированный запрос выполнит разрушительное действие.

Типовые ошибки и их решение

Даже опытные разработчики сталкиваются с проблемами при работе с реквизитами форм в запросах. Рассмотрим самые распространённые:

  1. Ошибка «Параметр не найден»:

    Причина: имя параметра в тексте запроса не совпадает с именем в методе УстановитьПараметр(). Проверьте регистр и опечатки.

  2. Запрос возвращает пустой результат:

    Возможные причины:

    • 🔸 Значение реквизита формы — NULL (не установлено). Добавьте проверку: Если ЗначениеЗаполнено(ЭлементыФормы.Поле.Значение) Тогда...
    • 🔸 Неверный тип параметра (например, передаёте строку в параметр типа Дата).
    • 🔸 В тексте запроса используется = вместо ПОДОБНО для строкового поиска.

  • Ошибка приведения типов:

    Например, пытаетесь сравнить Ссылка на справочник с УникальныйИдентификатор. Используйте явное приведение: ГДЕ Ссылка = &Ссылка.Ссылка.

  • Для диагностики ошибок используйте отладчик 1С:

    • 🐞 Проверьте значение реквизита формы перед передачей в запрос (Сообщить(ЭлементыФормы.Поле.Значение)).
    • 🐞 Выведите текст сформированного запроса в сообщение: Сообщить(Запрос.ТекстЗапроса).
    • 🐞 Используйте ПошаговыйРежим для отслеживания выполнения.

    💡

    Всегда проверяйте фактические значения реквизитов формы перед передачей в запрос. Часто проблема кроется не в синтаксисе запроса, а в пустых или некорректных данных на форме.

    Оптимизация производительности

    Неправильная работа с реквизитами формы может тормозить систему, особенно в крупных базах. Следуйте этим правилам:

    • 🚀 Минимизируйте динамическое формирование текста запроса. Предпочитайте параметры — они позволяют использовать кэш планов выполнения.
    • 🚀 Ограничивайте объём временных таблиц. Если передаёте тысячи строк, разбейте их на пакеты по 1000–2000 записей.
    • 🚀 Избегайте избыточных данных в параметрах. Например, если нужно передать только Ссылку на объект, не передавайте весь объект целиком.
    • 🚀 Используйте индексируемые поля в условиях. Фильтрация по неиндексируемым полям (например, по произвольному текстовому комментарию) замедляет запрос.

    Пример оптимизированного запроса с учётом индексов:

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

    "ВЫБРАТЬ ПЕРВЫЕ 100

    | Документ.ЗаказПокупателя.Ссылка КАК Ссылка,

    | Документ.ЗаказПокупателя.Дата КАК Дата

    |ИЗ

    | Документ.ЗаказПокупателя КАК Документ

    |ГДЕ

    | Документ.Контрагент = &Контрагент // Поле Контрагент индексировано

    | И Документ.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания // Поле Дата индексировано

    |УПОРЯДОЧИТЬ ПО

    | Дата УБЫВ";

    ⚠️ Внимание: В управляемых формах значения реквизитов могут обновляться асинхронно (например, при изменении поля на сервере). Если запрос выполняется до завершения обновления, он получит устаревшие данные. Используйте событие ПриИзменении или метод ОжидатьЗавершенияОбработки().

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

    Рассмотрим реальные сценарии, где требуется передача реквизитов формы в запрос:

    Пример 1: Поиск по наименованию с учётом регистра

    Если нужно искать без учёта регистра, используйте функцию ВРЕГ():

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

    "ВЫБРАТЬ

    | Справочник.Контрагенты.Ссылка КАК Ссылка

    |ИЗ

    | Справочник.Контрагенты КАК Контрагенты

    |ГДЕ

    | ВРЕГ(Контрагенты.Наименование) ПОДОБНО ВРЕГ(&ПоисковаяСтрока)";

    Запрос.УстановитьПараметр("ПоисковаяСтрока", "%" + ЭлементыФормы.ПолеПоиска.Значение + "%");

    Пример 2: Фильтрация по динамическому списку

    Если на форме есть список выбранных элементов (например, чекбоксы), передавайте их через массив:

    МассивКонтрагентов = Новый Массив;
    

    Для Каждого Элемент Из ЭлементыФормы.СписокКонтрагентов.ВыбранныеСтроки Цикл

    МассивКонтрагентов.Добавить(Элемент.Контрагент);

    КонецЦикла;

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

    "ВЫБРАТЬ

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

    |ИЗ

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

    |ГДЕ

    | Реализация.Контрагент В (&СписокКонтрагентов)";

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

    Пример 3: Работа с иерархическими справочниками

    Если нужно получить данные по группе справочника (например, все номенклатурные позиции из категории), используйте функцию ПОДЧИНЕНЫ():

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

    "ВЫБРАТЬ

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

    |ИЗ

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

    |ГДЕ

    | Номенклатура.Родитель = &Группа ИЛИ Номенклатура.Ссылка ПОДЧИНЕНЫ &Группа";

    Запрос.УстановитьПараметр("Группа", ЭлементыФормы.ПолеГруппы.Значение);

    💡

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

    FAQ: Ответы на частые вопросы

    Можно ли передать в запрос значение реквизита формы, который ещё не сохранён (например, из новой строки табличной части)?

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

    НоваяСтрока = ЭлементыФормы.ТабличнаяЧасть.Добавить();
    

    Запрос.УстановитьПараметр("Наименование", НоваяСтрока.Наименование); // Передаём значение, а не ссылку

    Если требуется ссылка, сначала сохраните документ (Объект.Записать()).

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

    Для объектных типов (справочники, документы) передавайте ссылку на объект, а не сам объект. Пример:

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

    В тексте запроса сравнивайте с полем типа Ссылка:

    ГДЕ Документ.Контрагент = &Контрагент
    Почему запрос игнорирует изменения значения реквизита формы?

    В управляемых формах значения реквизитов могут обновляться асинхронно. Чтобы гарантированно получить актуальное значение:

    1. Используйте событие ПриИзменении для поля:
    2. &НаКлиенте
      

      Процедура ПолеДатыПриИзменении(Элемент)

      ОбновитьДанныеЗапроса();

      КонецПроцедуры

    3. Либо принудительно обновите форму перед выполнением запроса:
    4. ОжидатьЗавершенияОбработки();
    Как передать в запрос значение реквизита, который может быть NULL?

    Используйте конструкцию ЗНАЧЕНИЕЗАПОЛНЕНО() для проверки и условную логику:

    Если ЗначениеЗаполнено(ЭлементыФормы.ПолеДаты.Значение) Тогда
    

    Запрос.Текст = "ГДЕ Дата = &Дата";

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

    Иначе

    Запрос.Текст = "ГДЕ Дата ЕСТЬ NULL";

    КонецЕсли;

    Или используйте функцию ВЫРАЗИТЬ() в запросе:

    ГДЕ ВЫРАЗИТЬ(Дата КАК Строка) = ВЫРАЗИТЬ(&Дата КАК Строка)
    Можно ли передавать в запрос данные из несохранённой формы?

    Да, но с оговорками:

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

    Пример корректной передачи несозранённого значения:

    Запрос.УстановитьПараметр("НовыйКод", ЭлементыФормы.ПолеКода.Значение); // Передаём строку, а не ссылку