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

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

При разработке отчетов «ручным» запросом (без использования системы компоновки данных — СКД) программисты часто сталкиваются с проблемой: если пользователь не заполнил отбор на форме, запрос возвращает пустой результат или работает некорректно — для этой задачи есть консоль запросов и СКД для отладки. Это происходит потому, что условие типа Номенклатура В (&СписокНоменклатуры) жестко ограничивает выборку, а пустой список в 1С при сравнении через оператор В всегда дает ложное значение.

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

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

Рассмотрим наиболее популярный и простой в реализации метод, на котором остановился автор темы. Суть заключается во введении дополнительного булевого параметра, который «выключает» условие, если отбор не заполнен — в этом поможет обработка для создания гибких фильтров-запросов.

Проанализируем логику условия. Нам нужно, чтобы данные выводились, если (Отбор Выключен) ИЛИ (Поле соответствует значению). Разберем по шагам, как это реализовать в коде:

  1. Подготовим параметры в программном модуле перед выполнением запроса.
  2. Проверим, заполнил ли пользователь список значений или ссылку.
  3. Передадим результат проверки в запрос в виде логического флага.

Пример программной подготовки:


// Предположим, СписокПроизводителей — это параметр с формы
ОтборПоПроизводителюВыкл = (СписокПроизводителей.Количество() = 0);

Запрос.УстановитьПараметр("ОтборПоПроизводителюВыкл", ОтборПоПроизводителюВыкл);
Запрос.УстановитьПараметр("Производители", СписокПроизводителей);

Теперь посмотрим на текст самого запроса. В виртуальной таблице или секции ГДЕ мы прописываем следующее условие:


ГДЕ
    (&ОтборПоПроизводителюВыкл ИЛИ Номенклатура.Производитель В (&Производители))

Почему это работает? Если список пуст, флаг &ОтборПоПроизводителюВыкл принимает значение Истина. Согласно правилам булевой логики, если первая часть выражения с оператором ИЛИ верна, то все выражение становится истинным для каждой строки таблицы, и фильтрация фактически отключается.

Способ 2. Динамическое формирование текста запроса

Хотя первый способ удобен, он имеет недостаток в плане производительности на огромных таблицах (так называемая проблема SARGability) — её решит анализ производительности запросов и планов выполнения. Оптимизатор SQL-сервера иногда не может эффективно использовать индексы при наличии условий с ИЛИ. В таких случаях мы рекомендуем использовать динамическую модификацию текста запроса.

Рассмотрим, как это сделать правильно. Вместо того чтобы оставлять условие в запросе навсегда, мы будем добавлять его только тогда, когда это необходимо. Выясним, как реализовать этот алгоритм:

  1. В базовом тексте запроса оставляем «якорь» или заранее прописанное условие.
  2. Если параметр не заполнен, мы просто вырезаем это условие из текста перед его выполнением.

Пример реализации с использованием функции СтрЗаменить:


ТекстУсловия = "И Номенклатура.Производитель В (&Производители)";

Если СписокПроизводителей.Количество() = 0 Тогда
    // Если отбор не нужен, заменяем условие на пустую строку
    Запрос.Текст = СтрЗаменить(Запрос.Текст, ТекстУсловия, "");
Иначе
    Запрос.УстановитьПараметр("Производители", СписокПроизводителей);
КонецЕсли;

Этот метод гарантирует, что в СУБД уйдет максимально «чистый» и быстрый SQL-код без лишних логических проверок.

Способ 3. Использование расширений языка запросов (Фигурные скобки)

Если ваш отчет построен на базе ПостроителяОтчетов (что часто встречается в «старых» отчетах на обычных формах, как в примере автора), можно воспользоваться конструкцией с фигурными скобками {}. Это встроенный механизм 1С, который управляет условиями автоматически.

Посмотрим на пример синтаксиса в тексте запроса:


ВЫБРАТЬ
    Номенклатура,
    Склад,
    КоличествоОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, {Склад.* КАК Склад})

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

Способ 4. Обработка пустых ссылок

Иногда задача стоит иначе: нужно вывести данные либо по конкретному производителю, либо те, где производитель вообще не указан (пустая ссылка). В этом случае логика «вывести всё» дополняется проверкой на пустоту.

Проанализируем ситуацию, когда нам нужно включить пустые значения в отбор:


ГДЕ
    (Номенклатура.Производитель В (&Производители) 
    ИЛИ Номенклатура.Производитель = ЗНАЧЕНИЕ(Справочник.Производители.ПустаяСсылка))

Но будьте осторожны: если ваша цель — именно отключение фильтра, этот способ не подойдет, так как он лишь добавит товары без производителя к выбранному списку, но не покажет всех остальных производителей.

Профессиональные рекомендации по производительности

Подведем итог и выберем лучший подход в зависимости от условий задачи (поможет инструментарий для разработки и проверки синтаксиса 1С):

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

← На главную