При разработке отчетов и обработок на платформе 1С:Предприятие часто возникает задача: получить данные с фильтром по конкретному значению (например, по менеджеру), но если пользователь оставил поле выбора пустым — вывести все записи без ограничений. В этой статье мы разберем, почему стандартные механизмы могут не срабатывать, и рассмотрим три надежных способа реализации такой логики.
{} не работает в обычном запросе?Проанализируем типичную ошибку начинающих разработчиков. Использование фигурных скобок {ГДЕ ...} — это синтаксис, предназначенный исключительно для Системы компоновки данных (СКД) или Построителя отчета. Когда мы пишем обычный объект Запрос и устанавливаем его текст через Запрос.Текст = "...", платформа воспринимает всё содержимое внутри фигурных скобок как комментарий и просто игнорирует его при выполнении на уровне СУБД.
Для того чтобы эти условия заработали, запрос должен быть обработан специальным механизмом, который «развернет» эти скобки в реальное условие ГДЕ. Если же вы используете Запрос.Выполнить(), вам нужно применять другие подходы.
ВЫБОРРазберем самый простой вариант, который не требует динамического изменения текста запроса. Мы можем прописать логику проверки параметра прямо в секции ГДЕ. Идея заключается в том, что условие должно возвращать Истина либо при совпадении значений, либо если параметр не заполнен.
Рассмотрим пример кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КонтрагентыМенеджеры.Ссылка КАК Контрагент,
| КонтрагентыМенеджеры.МенеджерПокупателя
|ИЗ
| Справочник.Контрагенты.МенеджерыПокупателя КАК КонтрагентыМенеджеры
|ГДЕ
| ВЫБОР
| КОГДА &Менеджер = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) ТОГДА ИСТИНА
| ИНАЧЕ КонтрагентыМенеджеры.МенеджерПокупателя = &Менеджер
| КОНЕЦ";
Запрос.УстановитьПараметр("Менеджер", Менеджер);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Важный нюанс: этот метод отлично подходит для небольших таблиц. Однако стоит помнить, что использование сложных логических условий в ГДЕ может помешать СУБД эффективно использовать индексы, что приведет к замедлению работы на огромных объемах данных.
Также обратите внимание на типы данных. Если параметр &Менеджер имеет составной тип, проверка на ПустаяСсылка конкретного справочника может не сработать. В таких случаях надежнее передавать Неопределено и проверять на него.
Проанализируем ситуацию, когда нам важна максимальная производительность. Чтобы СУБД построила оптимальный план выполнения, в тексте запроса не должно быть лишних условий. Мы будем добавлять условие ГДЕ только тогда, когда параметр действительно заполнен.
Посмотрим, как это реализовать на практике:
ТекстУсловия = "";
Если ЗначениеЗаполнено(Менеджер) Тогда
ТекстУсловия = "ГДЕ КонтрагентыМенеджеры.МенеджерПокупателя = &Менеджер";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КонтрагентыМенеджеры.Ссылка,
| КонтрагентыМенеджеры.МенеджерПокупателя
|ИЗ
| Справочник.Контрагенты.МенеджерыПокупателя КАК КонтрагентыМенеджеры
|" + ТекстУсловия;
Если ЗначениеЗаполнено(Менеджер) Тогда
Запрос.УстановитьПараметр("Менеджер", Менеджер);
КонецЕсли;
Этот метод считается наиболее «чистым» с точки зрения SQL, так как итоговый запрос будет содержать фильтр только в случае необходимости. Это гарантирует использование индекса по полю МенеджерПокупателя.
Если ваша задача подразумевает, что завтра условий может стать больше (по организации, по региону, по группе контрагентов), лучше сразу задействовать ПостроительОтчета. Этот объект умеет самостоятельно обрабатывать те самые фигурные скобки {}, которые игнорирует обычный запрос.
Выясним, как правильно настроить такой механизм. Для начала подготовим текст запроса с конструкциями построителя:
ТекстЗапроса =
"ВЫБРАТЬ
| КонтрагентыМенеджеры.Ссылка,
| КонтрагентыМенеджеры.МенеджерПокупателя
|ИЗ
| Справочник.Контрагенты.МенеджерыПокупателя КАК КонтрагентыМенеджеры
|{ГДЕ
| КонтрагентыМенеджеры.МенеджерПокупателя.* КАК Менджер}";
Построитель = Новый ПостроительОтчета(ТекстЗапроса);
// Если параметр Менеджер на форме заполнен, добавляем его в отбор построителя
Если ЗначениеЗаполнено(Менеджер) Тогда
НовыйОтбор = Построитель.Отбор.Добавить("Менджер");
НовыйОтбор.Значение = Менеджер;
НовыйОтбор.Использование = Истина;
КонецЕсли;
// Построитель сам сформирует правильный текст запроса с учетом отборов
Построитель.Выполнить();
Результат = Построитель.Результат.Выгрузить();
Использование построителя позволяет пользователю интерактивно добавлять любые отборы, если вывести ПостроительОтчета.Отбор на форму в виде табличного поля. Это гораздо мощнее и гибче, чем прописывание каждого условия вручную в коде.
Разберем еще один критический момент. В исходном вопросе данные выбираются из табличной части Справочник.Контрагенты.МенеджерыПокупателя.
РАЗЛИЧНЫЕ или группировку по ссылке контрагента.МенеджерПокупателя в табличной части справочника. Это критически важно для быстродействия.ЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка) работает только для конкретных типов. Если вы работаете с составным типом, используйте проверку на НЕОПРЕДЕЛЕНО или проверяйте заполненность параметра в коде перед запуском запроса.Таким образом, выбор метода зависит от сложности задачи. Для разового простого запроса достаточно конструкции ВЫБОР. Для высоконагруженных систем лучше использовать динамическую сборку текста, а для гибких отчетов в обычных формах — ПостроительОтчета.