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

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

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

Но есть и подводные камни: неправильное использование параметров может привести к ошибкам выполнения или даже падению производительности. Например, передача коллекции как параметра в старых версиях платформы работала иначе, чем в современных. Мы подробно разберем все эти нюансы.

1. Основы синтаксиса: как добавить параметр в запрос

Базовый синтаксис добавления параметров в запросы выглядит так: значения передаются через метод УстановитьПараметр() перед выполнением запроса. Рассмотрим простейший пример с одним параметром:

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

| Номенклатура.Артикул = &Артикул";

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

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

Здесь &Артикул — это именованный параметр, который будет заменен на значение "ABC123" при выполнении. Обратите внимание на символ & перед именем параметра — это обязательный синтаксис.

Платформа 1С:Предприятие 8.3 поддерживает два типа параметров:

  • 🔹 Именованные — указываются с символом & (например, &ДатаНачала). Рекомендуемый способ, так как код становится более читаемым.
  • 🔹 Позиционные — обозначаются знаком ? и заменяются по порядку (первый ? — первый параметр, второй ? — второй и т.д.). Менее наглядно, но иногда удобно для простых запросов.

Пример с позиционными параметрами:

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| ЗаказПокупателя.Дата МЕЖДУ ? И ?";

Запрос.УстановитьПараметр(1, НачалоПериода); // Первый параметр

Запрос.УстановитьПараметр(2, КонецПериода); // Второй параметр

📊 Какой тип параметров вы используете чаще?
Именованные (¶m)
Позиционные (?)
Оба типа примерно equally
Не использую параметры

2. Работа с разными типами данных

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

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| Реализация.Дата = &ДатаДок";

Запрос.УстановитьПараметр("ДатаДок", Формат(ТекущаяДата(), "ДФ=yyyy-MM-dd"));

Для коллекций (массивов, списков значений) используется специальный синтаксис с ключевым словом В:

СписокНоменклатуры = Новый СписокЗначений;

СписокНоменклатуры.Добавить("Товар1");

СписокНоменклатуры.Добавить("Товар2");

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

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

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

Особое внимание требуют NULL-значения. Если параметр может быть не задан, используйте конструкцию ЕСТЬ NULL:

Если Не ЗначениеЗаполнено(ПараметрПоиска) Тогда

Запрос.Текст = "ВЫБРАТЬ ... ГДЕ Поле = &Параметр ИЛИ &Параметр ЕСТЬ NULL";

КонецЕсли;

Тип данных Пример параметра Особенности
Строка &Наименование = "Товар" Автоматическое экранирование кавычек
Число &Количество > 10 Поддерживаются все числовые типы (Число, Дробь)
Дата &Дата МЕЖДУ ДАТАВРЕМЯ(2023,1,1) И ДАТАВРЕМЯ(2023,12,31) Рекомендуется использовать Формат() для унификации
Булево &Активен = ИСТИНА В запросе преобразуется в 1 или 0
Ссылка &Контрагент = &СсылкаНаКонтрагента Работает со всеми справочниками и документами
💡

Для ускорения выполнения запросов с параметрами-коллекциями используйте временные таблицы вместо прямой подстановки большого списка значений.

3. Продвинутые техники: динамические параметры и оптимизация

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

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

Условия = Новый Массив;

Если ЗначениеЗаполнено(Фильтр.ДатаНачала) Тогда

Условия.Добавить("Дата >= &ДатаНачала");

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

КонецЕсли;

Если ЗначениеЗаполнено(Фильтр.Контрагент) Тогда

Условия.Добавить("Контрагент = &Контрагент");

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

КонецЕсли;

Если Условия.Количество() > 0 Тогда

ТекстЗапроса = ТекстЗапроса + " " + СтрСоединить(Условия, " И ");

Иначе

ТекстЗапроса = ТекстЗапроса + " 1=1"; // Если нет условий

КонецЕсли;

Для оптимизации производительности при работе с большими объемами данных:

  • 🚀 Используйте временные таблицы для промежуточных результатов вместо вложенных запросов с параметрами.
  • 📊 Ограничивайте выборку с помощью ПЕРВЫЕ или РАЗЛИЧНЫЕ, если не нужны все записи.
  • Избегайте параметров в функциях типа НАЧИНАЕТСЯ или СОДЕРЖИТ — это блокирует использование индексов.

Критическая особенность платформы 8.3.20+: при передаче коллекции как параметра в запрос с оператором В сервер автоматически оптимизирует выполнение, преобразуя его в временную таблицу. В более ранних версиях это могло приводить к полному сканированию таблиц.

Использовать именованные параметры вместо конкатенации строк|

Проверять заполненность параметров перед установкой|

Ограничивать глубину вложенных запросов с параметрами|

Тестировать производительность с разными типами данных-->

4. Типичные ошибки и как их избежать

Ошибка №1: Пропущенный символ & перед параметром. В этом случае платформа воспринимает текст как часть запроса, что приводит к синтаксической ошибке:

// Неверно:

ГДЕ Дата = ДатаНачала // Ошибка: ДатаНачала не объявлена

// Правильно:

ГДЕ Дата = &ДатаНачала

Ошибка №2: Несоответствие типов данных. Например, передача строки вместо даты:

Запрос.УстановитьПараметр("Дата", "01.01.2023");  // Ошибка!

// Правильно:

Запрос.УстановитьПараметр("Дата", Дата(2023, 1, 1));

Ошибка №3: Использование параметров в выражениях без явного приведения типов. Это может привести к неожиданным результатам:

// Проблема:

ГДЕ Сумма > &Порог // Если &Порог строка, сравнение будет некорректным

// Решение:

ГДЕ Сумма > ЧИСЛО(&Порог)

⚠️ Внимание: В версиях платформы ниже 8.3.18 передача пустого списка значений как параметра могла приводить к ошибке выполнения. Всегда проверяйте коллекции на пустоту перед установкой параметра.

Ошибка №4: Избыточные параметры. Например, когда один и тот же параметр используется многократно в запросе, но устанавливается несколько раз с разными значениями. Последний УстановитьПараметр() перезаписывает предыдущие.

Для отладки сложных запросов используйте метод Запрос.ПолучитьТекстЗапроса() — он покажет финальный текст с подставленными параметрами (в режиме отладки).

5. Работа с параметрами в разных версиях 1С

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

Версия платформы Особенности работы с параметрами Рекомендации
8.2 и ниже Поддержка только позиционных параметров (?) Используйте конкатенацию с экранированием для именованных параметров
8.3.1–8.3.9 Появились именованные параметры, но ограниченная поддержка коллекций Для больших списков используйте временные таблицы
8.3.10–8.3.17 Улучшена работа с датами и NULL-значениями в параметрах Можно использовать ЕСТЬ NULL напрямую в условиях
8.3.18+ Оптимизация запросов с параметрами-коллекциями (автоматическое создание временных таблиц) Рекомендуемая версия для работы с большими данными

Для обеспечения совместимости кода между версиями:

  • 🔧 Всегда проверяйте заполненность параметров перед установкой.
  • 📋 Используйте универсальные форматы дат (yyyy-MM-dd).
  • 🔄 Для коллекций реализуйте альтернативную логику через временные таблицы в старых версиях.
⚠️ Внимание: В конфигурациях с поддержкой нескольких версий платформы (например, 1С:ERP) тестируйте запросы с параметрами на всех целевых релизах. Некоторые оптимизации могут работать по-разному.

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

Пример 1. Фильтрация по нескольким критериям:

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

"ВЫБРАТЬ

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

| Документ.ПоступлениеТоваров.Дата КАК Дата

|ИЗ

| Документ.ПоступлениеТоваров КАК Поступление

|ГДЕ

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

| И (&Контрагент ЕСТЬ NULL ИЛИ Поступление.Контрагент = &Контрагент)

| И (&Склад ЕСТЬ NULL ИЛИ Поступление.Склад = &Склад)";

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

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

Запрос.УстановитьПараметр("Контрагент", Фильтр.Контрагент); // Может быть NULL

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

Пример 2. Использование параметра в подзапросе:

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

"ВЫБРАТЬ

| Товар.Наименование,

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

|ИЗ

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

|ГДЕ

| Товар.Артикул В (

| ВЫБРАТЬ РАЗЛИЧНЫЕ Артикул

| ИЗ Документ.ЗаказПокупателя.Товары

| ГДЕ ЗаказПокупателя.Ссылка = &СсылкаНаЗаказ

| )";

Запрос.УстановитьПараметр("СсылкаНаЗаказ", ТекущийДокумент.Ссылка);

Пример 3. Динамическое формирование списка полей:

Как работает динамическое формирование полей?

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

ПоляДляВыбора = Новый Массив;

ПоляДляВыбора.Добавить("Номенклатура.Наименование КАК Наименование");

Если ПоказыватьЦены Тогда

ПоляДляВыбора.Добавить("Цена КАК Цена");

ПоляДляВыбора.Добавить("Сумма КАК Сумма");

КонецЕсли;

Если ПоказыватьОстатки Тогда

ПоляДляВыбора.Добавить("Остаток КАК Остаток");

КонецЕсли;

ТекстЗапроса = "ВЫБРАТЬ " + СтрСоединить(ПоляДляВыбора, ", ") + "

|ИЗ РегистрНакопления.ОстаткиТоваров...";

💡

Для сложных динамических запросов всегда используйте подготовленные выражения (Prepared Statements) через параметры — это защищает от SQL-инъекций и улучшает производительность.

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

Параметры сами по себе не ухудшают производительность, но их неправильное использование может приводить к полным сканированиям таблиц. Основные правила оптимизации:

1. Избегайте параметров в функциях над полями:

// Плохо (индекс не используется):

ГДЕ НАЧИНАЕТСЯ(Номенклатура.Наименование, &Префикс)

// Хорошо:

ГДЕ Номенклатура.Наименование ПОДОБНО &Шаблон

2. Используйте временные таблицы для больших коллекций:

// Вместо:

ГДЕ Товар В (&СписокТоваров) // Для списка из 1000+ элементов

// Лучше:

ВЫБРАТЬ ...

В ТВ_Товары

УСТАНОВИТЬ ;

ВСТАВИТЬ В ТВ_Товары (Товар)

ВЫБРАТЬ &СписокТоваров.Товар ИЗ &СписокТоваров КАК СписокТоваров;

ГДЕ Товар В (ВЫБРАТЬ Товар ИЗ ТВ_Товары)

3. Ограничивайте диапазоны дат:

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

ГДЕ Дата МЕЖДУ &ДатаНачала И &ДатаОкончания

// Вместо:

ГДЕ Дата >= &ДатаНачала

4. Тестируйте планы выполнения:

В конфигураторе можно включить отображение плана выполнения запроса (меню Сервис → Параметры → Отладка → Показывать план выполнения запроса). Это поможет выявить "узкие места".

⚠️ Внимание: В кластерных базах данных (например, при работе с 1С:SQL или PostgreSQL) неэффективные запросы с параметрами могут блокировать таблицы. Всегда тестируйте нагрузку в условиях, близких к боевым.

8. Альтернативные подходы: когда параметры не подходят

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

1. Конкатенация строк с экранированием:

Подходит для простых значений, когда динамически формируется часть запроса:

ИмяПоля = "Наименование";

ЗначениеПоля = ЭкранироватьСтроку(ПользовательскийВвод);

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

|ГДЕ " + ИмяПоля + " = '" + ЗначениеПоля + "'";

2. Временные таблицы:

Идеальны для сложных фильтров или когда нужно многократно использовать один набор данных:

// Создание временной таблицы

Запрос.Текст = "ВЫБРАТЬ * В ТВ_Фильтр ИЗ &ТаблицаФильтров КАК Фильтры";

Запрос.УстановитьПараметр("ТаблицаФильтров", ТаблицаЗначенийСФильтрами);

Запрос.Выполнить();

// Использование в основном запросе

Запрос.Текст = "ВЫБРАТЬ Товары.* ИЗ Справочник.Номенклатура КАК Товары

|ГДЕ Товары.Артикул В (ВЫБРАТЬ Артикул ИЗ ТВ_Фильтр)";

3. Хранимые процедуры (для внешних СУБД):

При работе с MS SQL Server или PostgreSQL можно перенести логику в хранимые процедуры, где параметры обрабатываются на уровне СУБД.

4. Объектная модель:

Для простых выборок иногда эффективнее использовать объекты напрямую:

Выборка = Справочники.Номенклатура.Выбрать();

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

Если Выборка.Артикул = ИскомыйАртикул Тогда

// Обработка

КонецЕсли;

КонецЦикла;

Подход Когда использовать Ограничения
Параметры Стандартные запросы, динамическая фильтрация Ограничения на типы данных в старых версиях
Конкатенация Динамическое формирование структуры запроса Риск SQL-инъекций, сложное экранирование
Временные таблицы Сложные фильтры, большие наборы данных Требует дополнительных запросов для создания
Объектная модель Простые выборки, работа с отдельными объектами Низкая производительность для больших данных
💡

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

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

Можно ли использовать параметры в запросах к внешним источникам данных (HTTP-сервисы, веб-АПИ)?

Нет, механизм параметров УстановитьПараметр() работает только для запросов к базе данных . Для внешних источников нужно формировать строку запроса вручную с экранированием или использовать специализированные библиотеки для работы с API.

Пример для HTTP-запроса:

Адрес = "https://api.example.com/data?param=" + ЭкранироватьСтрокуДляURL(Параметр);

Ответ = HTTPСоединение.Получить(Адрес);

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

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

  1. Преобразовать таблицу во временную таблицу базы данных.
  2. Выгрузить данные в массив и передать как параметр-коллекцию (для небольших наборов данных).
  3. Использовать объектную модель вместо запроса.

Пример с временной таблицей:

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

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

Запрос.Текст = "ВЫБРАТЬ * В ТВ_Данные ИЗ &ТаблицаДанных КАК Данные";

Запрос.УстановитьПараметр("ТаблицаДанных", ИсходнаяТаблицаЗначений);

Запрос.Выполнить();

// 2. Используем её в основном запросе

Запрос.Текст = "ВЫБРАТЬ Товары.* ИЗ Справочник.Номенклатура КАК Товары

|ГДЕ Товары.Ссылка В (ВЫБРАТЬ Ссылка ИЗ ТВ_Данные)";

Почему запрос с параметром выполняется дольше, чем без него?

Это может происходить по нескольким причинам:

  • 🔍 Сервер не использует индексы из-за неоптимального условия с параметром (например, НАЧИНАЕТСЯ(Поле, &Параметр)).
  • 📊 Параметр передается как коллекция большого размера, что приводит к полному сканированию.
  • 🔄 В некоторых версиях платформы подготовка плана выполнения для параметризованного запроса занимает дополнительное время.

Решения:

  • Проверьте план выполнения запроса.
  • Замените функции над полями на эквивалентные конструкции (например, ПОДОБНО вместо НАЧИНАЕТСЯ).
  • Для больших коллекций используйте временные таблицы.

Как передать NULL в качестве значения параметра?

Для передачи NULL используйте специальное значение Неопределено:

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

В тексте запроса проверяйте на ЕСТЬ NULL:

ГДЕ (&Параметр ЕСТЬ NULL ИЛИ Поле = &Параметр)

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

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

Да, в пакетных запросах (с использованием + для объединения текстов) параметры работают так же, как и в обычных. Главное правило — устанавливать параметры после формирования полного текста пакетного запроса, но до его выполнения:

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

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

"ВЫБРАТЬ ... ГДЕ Поле1 = &Параметр1;

|

ВЫБРАТЬ ... ГДЕ Поле2 = &Параметр2;";

Запрос.УстановитьПараметр("Параметр1", Значение1);

Запрос.УстановитьПараметр("Параметр2", Значение2);

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

Обратите внимание, что в пакетных запросах параметры не наследуются между отдельными запросами в пакете — каждый запрос должен иметь свои собственные параметры.