Как реализовать необязательные отборы в запросе 1С, чтобы запрос работал корректно при пустых параметрах

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие часто возникает задача создания универсального запроса. Представим ситуацию: на форме отчета или обработки есть несколько реквизитов для фильтрации данных (например, Номенклатура, Склад, Период). Если пользователь заполнил все поля, запрос должен отработать по всем фильтрам. Однако, если пользователь оставил поле Номенклатура пустым, система должна проигнорировать этот отбор и вывести данные по всей номенклатуре.

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

Способ 1. Использование логического условия ИЛИ в запросе

Проанализируем самый простой и популярный метод, который позволяет оставить текст запроса статичным. Мы добавим в блок ГДЕ проверку на пустое значение параметра. Если параметр не заполнен, условие автоматически становится истинным для всех строк таблицы.

Рассмотрим пример кода в запросе:


ВЫБРАТЬ
    Продажи.Номенклатура КАК Номенклатура,
    Продажи.Количество КАК Количество
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    (Продажи.Номенклатура = &Номенклатура ИЛИ &Номенклатура = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка))
    И (Продажи.Склад = &Склад ИЛИ &Склад = ЗНАЧЕНИЕ(Справочник.Склад.ПустаяСсылка))

Разберем, как это работает. Если в параметр &Номенклатура передана пустая ссылка, то вторая часть условия &Номенклатура = ЗНАЧЕНИЕ(...) возвращает Истина. Поскольку используется оператор ИЛИ, всё выражение в скобках становится истинным для любой строки базы данных, и отбор фактически перестает действовать. Если же параметр заполнен, срабатывает первая часть условия Продажи.Номенклатура = &Номенклатура.

Важный нюанс: при установке параметров на стороне встроенного языка 1С нужно убедиться, что вы передаете именно тот тип "пустоты", который ожидается (ПустаяСсылка, Неопределено, пустая строка или 0).

Способ 2. Использование параметров-флагов

Иногда проверка на пустое значение внутри самого запроса может быть громоздкой (например, если тип параметра составной или это список значений). В таком случае удобно использовать вспомогательный параметр-флаг, который заранее вычисляется в коде 1С.

Посмотрим на пример реализации такого подхода:


// В модуле 1С подготовим параметры
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|    ЗаказКлиента.Ссылка КАК Ссылка
|ИЗ
|    Документ.ЗаказКлиента КАК ЗаказКлиента
|ГДЕ
|    (ЗаказКлиента.Партнер = &Партнер ИЛИ &ПартнерНеУказан)";

Запрос.УстановитьПараметр("Партнер", Объект.Партнер);
Запрос.УстановитьПараметр("ПартнерНеУказан", НЕ ЗначениеЗаполнено(Объект.Партнер));

Этот метод считается более "чистым" с точки зрения логики запроса, так как мы выносим проверку заполнения в код приложения. Функция ЗначениеЗаполнено() универсальна: она корректно определит пустоту для ссылок, строк, дат и массивов.

Способ 3. Изящное использование оператора В

Проанализируем еще один интересный вариант, который позволяет сократить запись условия ИЛИ. Мы можем использовать оператор В, перечисляя в скобках само поле и эталонное пустое значение.


ГДЕ
    &Номенклатура В (Т.Номенклатура, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка))
    И &Дата В (Т.Дата, ДАТАВРЕМЯ(1, 1, 1))

Этот синтаксис работает зеркально: если переданный параметр &Номенклатура совпадает со значением в строке таблицы ИЛИ является пустым, условие выполняется. Однако будьте осторожны: такой подход может быть менее интуитивно понятным для других разработчиков, читающих ваш код.

Проблема производительности: SARGability и индексы

Выясним причину, по которой опытные разработчики часто критикуют вышеописанные методы (особенно Способ 1). Использование оператора ИЛИ в секции ГДЕ часто делает запрос non-SARGable (Search Argumentable). Это означает, что оптимизатор SQL-сервера может не справиться с выбором правильного индекса.

Когда вы пишете ГДЕ (Поле = &Пар ИЛИ &ПарПуст), SQL-сервер не всегда может применить Index Seek (быстрый поиск по индексу). Вместо этого он может прибегнуть к Index Scan или Table Scan — полному сканированию таблицы. На малых объемах данных это незаметно, но на таблицах с миллионами записей такой "универсальный" запрос может выполняться в десятки раз медленнее, чем прямой отбор.

Рекомендация: если производительность критична, используйте динамическое формирование текста запроса.

Способ 4. Динамическая сборка текста запроса

Разберем, как программно изменять текст запроса в зависимости от заполнения параметров. Этот метод гарантирует максимальную производительность, так как в итоговом SQL-запросе не будет лишних условий ИЛИ.


ТекстЗапроса = 
"ВЫБРАТЬ
|    Номенклатура.Ссылка КАК Ссылка
|ИЗ
|    Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|    ЭтоГруппа = Ложь";

Если ЗначениеЗаполнено(Объект.Родитель) Тогда
    ТекстЗапроса = ТекстЗапроса + " И Номенклатура.Родитель = &Родитель";
КонецЕсли;

Запрос = Новый Запрос(ТекстЗапроса);
Если ЗначениеЗаполнено(Объект.Родитель) Тогда
    Запрос.УстановитьПараметр("Родитель", Объект.Родитель);
КонецЕсли;

Этот способ позволяет гибко управлять логикой. Например, если пользователь выбрал конкретную номенклатуру, мы используем оператор =, а если выбрал группу — оператор В ИЕРАРХИИ. Это именно то, что требовалось автору вопроса для повышения гибкости отчета.

Способ 5. Система компоновки данных (СКД)

Как справедливо заметили участники обсуждения, СКД — это мощнейший инструмент, который берет всю рутину по управлению отборами на себя. Даже если вы не делаете отчет, а пишете программную обработку данных, вы можете использовать компоновщик макета.

В СКД достаточно просто описать запрос с параметрами. Если в настройках компоновщика параметр не установлен или флаг использования снят, СКД автоматически вырезает соответствующее условие из итогового запроса. Это "золотой стандарт" разработки в среде 1С 8.3.

Рассмотрим, как использовать расширение языка запросов для СКД:


ВЫБРАТЬ
    Номенклатура.Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
{ГДЕ
    Номенклатура.Ссылка.* КАК Ссылка}

Фигурные скобки {} обозначают необязательную часть. Если поле Ссылка не будет добавлено в отбор пользователем, эта часть запроса просто не попадет в исполняемый код SQL. Это позволяет сочетать читаемость кода и высокую скорость выполнения.

Итоги

Мы проанализировали различные подходы к решению задачи динамических фильтров. Подведем краткий итог:

  1. Для простых задач и небольших таблиц: используйте конструкцию (Поле = &Параметр ИЛИ &ФлагПустоты). Это быстро в реализации и сохраняет запрос читаемым.
  2. Для высоконагруженных систем: применяйте динамическую сборку текста запроса на встроенном языке, чтобы SQL-сервер мог эффективно использовать индексы.
  3. Для сложных отчетов: всегда отдавайте предпочтение СКД. Это сэкономит время на написание кода и обеспечит пользователю максимальную гибкость.
  4. Внимательно следите за типами: всегда проверяйте, что вы сравниваете (ПустаяСсылка, Неопределено или NULL), чтобы избежать неожиданных пустых результатов.

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

← На главную