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