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

Эта статья разбирает 5 рабочих способов передачи параметров — от элементарных подстановок до работы с временными таблицами и динамическим формированием текста запроса. Мы детально проанализируем плюсы и минусы каждого подхода, покажем реальные примеры кода с пояснениями, а также предостережём от типичных ошибок, которые тормозят выполнение или ведут к уязвимостям. Материал будет полезен как начинающим 1С-программистам, так и опытным специалистам, которые хотят оптимизировать существующие решения.

1. Базовая подстановка параметров через «ПараметрыЗапроса»

Самый простой и безопасный способ — использование коллекции ПараметрыЗапроса. Этот метод подходит для передачи примитивных типов данных: чисел, строк, дат, булевых значений. Главное преимущество — автоматическая защита от SQL-инъекций, так как платформа сама экранирует передаваемые значения.

Как это работает на практике? Сначала в тексте запроса указываете именованный параметр (например, &ДатаНачала), а затем добавляете его в коллекцию с реальным значением. Пример:

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

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

"ВЫБРАТЬ

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

| Документ.Дата КАК Дата

|ИЗ

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

|ГДЕ

| Документ.Дата >= &ДатаНачала

| И Документ.Дата <= &ДатаОкончания";

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

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

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

  • Плюсы: Простота, безопасность, поддержка всех версий платформы 8.x.
  • Минусы: Не подходит для передачи массивов или сложных структур (например, списка значений).
  • 🔹 Особенность: Имена параметров должны начинаться с & и не содержать пробелов.
⚠️ Внимание: Если передаёте дату/время, используйте функции НачалоДня()/КонецДня(), чтобы избежать проблем с временными зонами в распределённых базах.
📊 Какой способ передачи параметров вы используете чаще?
ПараметрыЗапроса
Временные таблицы
Динамический текст запроса
Хранимая процедура
Другой

2. Передача списков значений через временные таблицы

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

Алгоритм действий:

  1. Создаём временную таблицу с нужной структурой.
  2. Заполняем её данными (например, из массива или списка значений).
  3. Используем в основном запросе через ВНУТРЕННЕЕ СОЕДИНЕНИЕ или ГДЕ В.
// Создаём временную таблицу для фильтра по номенклатуре

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

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

"ВЫБРАТЬ

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

|ПОМЕСТИТЬ ВТНоменклатура

|ИЗ

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

|ГДЕ

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

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

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

// Основной запрос с использованием временной таблицы

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

"ВЫБРАТЬ

| Документ.Ссылка,

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

|ИЗ

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

|ГДЕ

| Документ.Номенклатура.Ссылка В (

| ВЫБРАТЬ

| ВТНоменклатура.Ссылка

| ИЗ

| ВТНоменклатура КАК ВТНоменклатура

| )";

Сценарий Рекомендуемый метод Пример данных
Фильтр по 1-2 значениям ПараметрыЗапроса Дата, ID документа
Фильтр по списку (10-1000 элементов) Временная таблица Список номенклатуры, контрагентов
Динамическое формирование условий Строка запроса + СтрЗаменить() Сложная логика с И/ИЛИ
⚠️ Внимание: Временные таблицы существуют только в рамках одного сеанса. Если запрос выполняется на сервере (например, в фоновом задании), убедитесь, что таблица создаётся в том же сеансе.

Создать объект Запрос|Указать ПОМЕСТИТЬ ВТ[Имя]|Заполнить параметры|Выполнить запрос на создание|Использовать ВТ в основном запросе-->

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

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

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

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

|ВЫБРАТЬ

| Документ.Ссылка,

| Документ.Дата

|ИЗ

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

|ГДЕ

| 1 = 1";

// Добавляем условия по дате, если заданы

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

ТекстЗапроса = ТекстЗапроса + Строка(Символы.ПС) +

" И Документ.Дата >= " + Формат(ДатаНачала, "ДЛФ='DT'") + "";

КонецЕсли;

// Добавляем фильтр по номенклатуре, если есть список

Если СписокНоменклатуры.Количество() > 0 Тогда

ТекстЗапроса = ТекстЗапроса + Строка(Символы.ПС) +

" И Документ.Номенклатура В (" + СтрСоединить(СписокНоменклатуры, ", ") + ")";

КонецЕсли;

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

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

  • Плюсы: Максимальная гибкость, возможность построения сложной логики.
  • Минусы: Риск SQL-инъекций, если не экранировать значения. Сложнее поддерживать код.
  • 🔹 Совет: Для дат используйте формат ДЛФ='DT', чтобы избежать проблем с региональными настройками.
Как защититься от SQL-инъекций при динамическом формировании?

Всегда экранируйте строковые параметры с помощью функции ЭкранироватьСтроку():

ИмяКонтрагента = ЭкранироватьСтроку(ПользовательскийВвод.Имя, Кавычка.Одиночная);

ТекстЗапроса = "... ГДЕ Контрагент.Наименование = '" + ИмяКонтрагента + "'";

Для чисел и дат используйте форматирование с ДЛФ или передавайте через ПараметрыЗапроса.

4. Использование хранимых процедур (для SQL-сервера)

Если ваша база 1С:Предприятие работает на Microsoft SQL Server или PostgreSQL, можно задействовать хранимые процедуры. Этот метод уместен для сложных отчётов или операций, которые выполняются регулярно. Процедура создаётся непосредственно в СУБД и вызывается из 1С через ВыполнитьПакетЗапросов().

Пример создания процедуры в SQL Server:

CREATE PROCEDURE [dbo].[GetSalesByPeriod]

@DateFrom DATETIME,

@DateTo DATETIME,

@ClientID UNIQUEIDENTIFIER = NULL

AS

BEGIN

SELECT

t._Reference_IDRRef AS DocumentRef,

t._Date_Time_IDRRef AS DocumentDate

FROM

_Document163 AS t -- РеализацияТоваровУслуг

WHERE

t._Date_Time_IDRRef >= @DateFrom

AND t._Date_Time_IDRRef <= @DateTo

AND (@ClientID IS NULL OR t._Fld174_IDRRef = @ClientID) -- Контрагент

END;

Вызов из 1С:

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

Запрос.Текст = "ВЫПОЛНИТЬ GetSalesByPeriod @DateFrom, @DateTo, @ClientID";

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

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

Запрос.УстановитьПараметр("ClientID", NULL); // NULL, если фильтр не нужен

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

⚠️ Внимание: Хранимые процедуры привязаны к конкретной СУБД. При переносе базы на другую платформу (например, с MSSQL на PostgreSQL) их придётся переписывать. Также учитывайте, что изменения в метаданных 1С не обновляют автоматически структуру таблиц в SQL — может потребоваться ручная синхронизация.
💡

Перед использованием хранимых процедур проверьте, поддерживает ли ваша версия 1С и СУБД этот функционал. Например, в файловом варианте работы процедуры недоступны.

5. Передача табличных данных через параметры (1С:Предприятие 8.3.14+)

Начиная с версии 8.3.14, платформа поддерживает передачу табличных значений непосредственно в параметрах запроса. Это упрощает работу со сложными фильтрами, где раньше приходилось создавать временные таблицы. Достаточно передать в параметр объект типа ТаблицаЗначений или РезультатЗапроса.

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

// Создаём таблицу с фильтрами

Фильтры = Новый ТаблицаЗначений;

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

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

// Заполняем данными

Строка = Фильтры.Добавить();

Строка.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка");

Строка.Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию("Стул офисный");

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

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

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| (Документ.Контрагент, Документ.Номенклатура) В (&Фильтры)";

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

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

  • Плюсы: Упрощает код, уменьшает количество временных таблиц, поддерживает сложные условия с несколькими полями.
  • Минусы: Работает только в новых версиях платформы (8.3.14+).
  • 🔹 Нюанс: Структура таблицы-параметра должна точно соответствовать полям в условии В().
💡

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

6. Продвинутые техники: массивы, JSON и внешние источники

Для нестандартных задач (например, интеграции с внешними системами) могут потребоваться нетривиальные подходы:

  • 📌 Массивы в параметрах: В новых версиях 1С поддерживается передача массивов через УстановитьПараметр(). Пример:
    Запрос.УстановитьПараметр("СписокID", Новый Массив(123, 456, 789));

    В запросе: ГДЕ Документ.Ссылка В (&СписокID).

  • 📌 JSON-параметры: Если данные приходят в формате JSON (например, из REST-API), их можно распарсить и передать в запрос через временную таблицу или табличный параметр.
  • 📌 Внешние источники: Для больших объёмов данных (миллионы записей) рассмотрите возможность использования ВНЕШНИЙ ИСТОЧНИК ДАННЫХ или FEDERATED TABLE (в PostgreSQL).

Пример работы с JSON:

// Получаем JSON из внешней системы

JSONТекст = ПолучитьДанныеИзAPI();

Данные = JSON.Прочитать(JSONТекст);

// Преобразуем в таблицу значений для запроса

ТаблицаФильтров = Новый ТаблицаЗначений;

ТаблицаФильтров.Колонки.Добавить("Код");

ТаблицаФильтров.Колонки.Добавить("Наименование");

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

Строка = ТаблицаФильтров.Добавить();

Строка.Код = Элемент.Код;

Строка.Наименование = Элемент.Наименование;

КонецЦикла;

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

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

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

Даже опытные разработчики иногда допускают ошибки при работе с параметрами в запросах. Вот самые распространённые из них и способы их решения:

Ошибка Причина Решение
Ошибка при выполнении запроса: Неопределённый параметр '&Параметр' Опечатка в имени параметра или отсутствует УстановитьПараметр() Проверьте регистр и наличие & перед именем. Используйте Запрос.Параметры.СписокПараметров() для диагностики.
Запрос выполняется очень долго Передача большого списка значений через В() вместо временной таблицы Для списков >100 элементов используйте временные таблицы или табличные параметры (8.3.14+).
Тип параметра не соответствует типу значения Пытаетесь передать строку в параметр, ожидающий дату (или наоборот) Явно преобразуйте тип: Дата(СтрокаДаты) или Формат(Дата, "ДФ='yyyy-MM-dd'").
SQL-инъекция Подстановка пользовательского ввода напрямую в текст запроса Всегда используйте ЭкранироватьСтроку() или ПараметрыЗапроса.
⚠️ Внимание: Если ваш запрос внезапно стал работать медленнее после добавления параметров, проверьте план выполнения запроса в Консоли запросов 1С. Часто проблема кроется в отсутствии индексов на полях, используемых в условиях с параметрами.

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

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

Нет, напрямую — нельзя. Но можно:

  1. Поместить результат первого запроса во временную таблицу и использовать её во втором запросе.
  2. В версиях 8.3.14+ передать РезультатЗапроса как табличный параметр (если структура данных совпадает).

Пример:

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

Запрос2.УстановитьПараметр("Данные", Результат1.Выгрузить());

Как передать NULL в параметр запроса?

Используйте константу NULL (без кавычек):

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

В тексте запроса проверяйте так:

ГДЕ Контрагент = &Контрагент ИЛИ (&Контрагент ЕСТЬ NULL)
Почему при передаче даты в параметр запрос не возвращает данные?

Чаще всего проблема в:

  • Несовпадении временных зон (используйте НачалоДня()/КонецДня()).
  • Неверном формате даты (для строковых параметров используйте Формат(Дата, "ДФ='yyyy-MM-dd'")).
  • Отсутствии индекса на поле даты в базе.

Проверьте фактическое значение параметра:

Сообщить(Запрос.Параметры.Получить("ДатаНачала"));
Как передать в запрос данные из формы (элементы управления)?summary>

Сначала получите значение из элемента формы, затем передайте его в запрос:

ДатаНачала = ЭлементыФормы.ДатаНачала.Значение;

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

Для списков (например, ПолеВыбора):

СписокКонтрагентов = ЭлементыФормы.Контрагенты.Значение;

Если ТипЗнч(СписокКонтрагентов) = Тип("Массив") Тогда

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

КонецЕсли;

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

Да, параметры работают одинаково для всех виртуальных таблиц, включая регистры накопления, сведений и бухгалтерии. Пример для регистра ТоварыНаСкладах:

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

"ВЫБРАТЬ

| РегистрНакопленияТоварыНаСкладахОстатки.Номенклатура,

| РегистрНакопленияТоварыНаСкладахОстатки.КоличествоОстаток

|ИЗ

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

|ГДЕ

| РегистрНакопленияТоварыНаСкладахОстатки.Склад = &Склад";

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

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