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