При создании отчетов, обработок или динамических списков в 1С:Предприятии часто возникает необходимость формировать запросы с изменяющимися условиями отбора. Вместо того, чтобы каждый раз переписывать текст запроса, мы можем использовать механизм передачи параметров. Это позволяет нам создавать гибкие и эффективные запросы, адаптирующиеся к различным входным данным.
Прежде чем перейти к конкретным примерам, давайте рассмотрим основные принципы работы с параметрами запросов:
Объявление параметра в тексте запроса: В языке запросов 1С параметр обозначается символом амперсанда (&) перед его именем. Это дает системе понять, что данное слово является не полем или значением, а местом для подстановки переменной. Например, мы можем объявить параметры &НачалоПериода или &Помещение.
Установка значения параметра: Для присвоения значения параметру перед выполнением запроса мы используем метод УстановитьПараметр() объекта Запрос. Первым аргументом метода мы передаем имя параметра в виде строки (без амперсанда), а вторым — его значение.
Посмотрим на пример:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Справочник.Контрагенты.Наименование
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.Код > &НачальныйКод";
// Устанавливаем значение для параметра "НачальныйКод"
Запрос.УстановитьПараметр("НачальныйКод", "000000001");
Разберем по шагам, как передавать параметры для фильтрации данных по обычным полям таблиц в запросе. Этот метод является наиболее часто используемым.
Предположим, перед нами стоит задача получить список номенклатуры и ее остатков на конкретном складе. Мы не хотим жестко указывать склад в тексте запроса, а хотим передавать его как параметр.
Проанализируем ситуацию:
Запрос.Посмотрим на пример кода:
// Шаг 1: Создаем новый объект Запрос
Запрос = Новый Запрос;
// Шаг 2: Определяем текст запроса с параметром &Склад
// Мы используем виртуальную таблицу "Остатки" регистра накопления "ТоварыНаСкладах"
Запрос.Текст = "ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
|ГДЕ
| ТоварыНаСкладахОстатки.Склад = &Склад"; // Здесь &Склад - наш параметр
// Шаг 3: Устанавливаем значение для параметра &Склад
// Допустим, мы хотим получить остатки по конкретному складу "Основной склад"
СсылкаНаСклад = Справочники.Склады.НайтиПоНаименованию("Основной склад");
Если СсылкаНаСклад <> Неопределено Тогда
Запрос.УстановитьПараметр("Склад", СсылкаНаСклад);
Иначе
Сообщить("Склад 'Основной склад' не найден! Проверьте наличие склада в базе.");
Возврат; // Выходим из процедуры, если склад не найден
КонецЕсли;
// Шаг 4: Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
// Шаг 5: Выбираем данные из результата запроса
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
// Шаг 6: Обходим выборку и выводим результат
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Сообщить("Номенклатура: " + ВыборкаДетальныеЗаписи.Номенклатура + ", Остаток: " + ВыборкаДетальныеЗаписи.КоличествоОстаток);
КонецЦикла;
В этом примере мы видим, как с помощью Запрос.УстановитьПараметр("Склад", СсылкаНаСклад) мы передали конкретную ссылку на элемент справочника "Склады" в наш запрос. Это позволяет нам легко менять склад, для которого формируется запрос, без изменения его текста.
Особый случай передачи параметров возникает при работе с виртуальными таблицами. Виртуальные таблицы (например, Остатки, СрезПоследних, ОстаткиИОбороты регистров) предоставляют агрегированные данные и могут принимать свои собственные параметры для формирования этих данных. Эти параметры передаются напрямую в функцию виртуальной таблицы.
Выясним причину, почему это важно: параметры виртуальных таблиц влияют на то, какие данные будут отобраны еще до того, как к ним применится общее условие ГДЕ. Это позволяет существенно оптимизировать запрос, уменьшая объем данных, с которыми приходится работать.
Рассмотрим подробнее ситуацию, упомянутую в исходной теме форума: "Отбор по "Помещение" надо загнать во второй параметр виртуальной таблицы". Это означает, что для некоторых виртуальных таблиц (часто для регистров, имеющих измерение "Помещение") отбор по этому измерению можно сделать на уровне самой виртуальной таблицы.
Посмотрим на пример. Допустим, у нас есть регистр накопления "ТоварыНаСкладах", который имеет измерения "Склад" и "Помещение". Мы хотим получить остатки товаров на конкретном складе и в конкретном помещении.
Вот как мы можем это сделать, передавая параметр &Помещение во второй аргумент функции виртуальной таблицы Остатки:
// Создаем новый объект Запрос
Запрос = Новый Запрос;
// Определяем текст запроса. Обратите внимание на второй параметр виртуальной таблицы "Остатки"
// Первый параметр - Период (обычно &КонецПериода)
// Второй параметр - Условие (например, "Помещение = &Помещение")
Запрос.Текст = "ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| &КонецПериода, // Первый параметр - Период
| Склад = &Склад И Помещение = &Помещение // Второй параметр - Условие отбора внутри виртуальной таблицы
| ) КАК ТоварыНаСкладахОстатки";
// Устанавливаем значения для всех параметров
// 1. Параметр для периода
Запрос.УстановитьПараметр("КонецПериода", ТекущаяДата());
// 2. Параметр для склада
СсылкаНаСклад = Справочники.Склады.НайтиПоНаименованию("Основной склад");
Если СсылкаНаСклад = Неопределено Тогда
Сообщить("Склад 'Основной склад' не найден!");
Возврат;
КонецЕсли;
Запрос.УстановитьПараметр("Склад", СсылкаНаСклад);
// 3. Параметр для помещения
СсылкаНаПомещение = Справочники.ПомещенияСкладов.НайтиПоНаименованию("ЗонаХранения1"); // Предполагаем наличие справочника ПомещенияСкладов
Если СсылкаНаПомещение = Неопределено Тогда
Сообщить("Помещение 'ЗонаХранения1' не найдено!");
Возврат;
КонецЕсли;
Запрос.УстановитьПараметр("Помещение", СсылкаНаПомещение);
// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
// Выбираем данные и обходим выборку
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Номенклатура: " + Выборка.Номенклатура + ", Остаток: " + Выборка.КоличествоОстаток);
КонецЦикла;
В этом примере мы видим, что параметры &Склад и &Помещение используются внутри второго аргумента функции Остатки(). Это позволяет виртуальной таблице сгенерировать данные, уже отфильтрованные по складу и помещению, что является более производительным подходом, чем фильтрация уже полученных данных в секции ГДЕ основного запроса. Заметьте, что &КонецПериода является первым параметром виртуальной таблицы и тоже должен быть установлен.
Таким образом, мы видим, что передача параметров в запросы 1С — это мощный инструмент для создания динамичных и производительных решений. Используя методы УстановитьПараметр() и правильно определяя параметры как в основном тексте запроса, так и внутри функций виртуальных таблиц, мы можем значительно повысить гибкость и эффективность наших разработок.