Как реализовать отчет по всем элементам справочника, если фильтр не выбран (множественный выбор)?

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

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

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

Проблема пустого списка значений в условии "В"

Разберем типичную ситуацию. В запросе используется условие: ГДЕ Док.Подразделение В (&Подразделение). Если в параметр &Подразделение передать пустой СписокЗначений, то с точки зрения SQL это условие превратится в нечто, что всегда возвращает ЛОЖЬ. В итоге отчет получится пустым, даже если данные в базе есть. Наша задача — сделать условие "прозрачным", если фильтр не задан.

Способ 1: Универсальное условие внутри запроса

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


|ГДЕ
|    (&НеИспользоватьОтбор ИЛИ Док.Подразделение В (&Подразделение))

Теперь проанализируем, как подготовить параметры перед выполнением запроса в модуле отчета:


// Предположим, что "ПодразделенияНаФорме" — это СписокЗначений с формы
Запрос.УстановитьПараметр("Подразделение", ПодразделенияНаФорме);

// Если список пуст, флаг устанавливается в ИСТИНА, и условие "В" игнорируется
Запрос.УстановитьПараметр("НеИспользоватьОтбор", ПодразделенияНаФорме.Количество() = 0);

В этом случае, если пользователь ничего не выбрал, выражение &НеИспользоватьОтбор станет равным ИСТИНА. Согласно правилам логики, все условие в скобках станет истинным для каждой строки таблицы, и фильтрация не произойдет.

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

Если вы хотите избежать лишних проверок внутри самого SQL-запроса (что актуально для высоконагруженных систем), можно прибегнуть к модификации текста запроса непосредственно перед его выполнением. Этот метод позволяет полностью удалить секцию ГДЕ, если отбор не требуется.

Рассмотрим пример реализации:


ТекстЗапроса = 
"ВЫБРАТЬ
|    Док.Ссылка КАК Ссылка,
|    Док.СуммаДокумента КАК Сумма
|ИЗ
|    Документ.ЗаказПокупателя КАК Док
|{ГДЕ_ОТБОР}"; // Метка-заполнитель

Если ПодразделенияНаФорме.Количество() > 0 Тогда
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "{ГДЕ_ОТБОР}", "ГДЕ Док.Подразделение В (&Подразделение)");
    Запрос.УстановитьПараметр("Подразделение", ПодразделенияНаФорме);
Иначе
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "{ГДЕ_ОТБОР}", "");
КонецЕсли;

Запрос.Текст = ТекстЗапроса;

Такой подход делает запрос максимально эффективным для СУБД, так как в план выполнения не попадают лишние логические условия.

Способ 3: Использование Построителя отчетов (Legacy-метод)

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

  1. Добавим поле Подразделение в текст запроса построителя.
  2. В коде формирования отчета обратимся к коллекции отборов.

ПостроительОтчетов.Текст = "ВЫБРАТЬ ... ИЗ Документ.Продажи КАК Продажи {ГДЕ Продажи.Подразделение.*}";
ПостроительОтчетов.ЗаполнитьНастройки();

// Если пользователь выбрал значения в списке на форме:
Если ПодразделенияНаФорме.Количество() > 0 Тогда
    Отбор = ПостроительОтчетов.Отбор.Подразделение;
    Отбор.Использование = Истина;
    Отбор.ВидСравнения = ВидСравнения.ВСписке;
    Отбор.Значение = ПодразделенияНаФорме;
КонецЕсли;

Если условие ПодразделенияНаФорме.Количество() > 0 не выполнится, построитель просто не включит фильтр по подразделениям в итоговый SQL-запрос. Это самый "правильный" путь для старых конфигураций 1С.

Типичные ошибки при работе со списками

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


// ОШИБОЧНЫЙ ПОДХОД
Спр = Справочники.Подразделения.Выбрать();
Пока Спр.Следующий() Цикл
    Подразделение.ЗагрузитьЗначения(Спр.Ссылка); // Ошибка: метод ЗагрузитьЗначения очищает список на каждой итерации!
КонецЦикла;

Почему это плохо:

Рекомендации по оптимизации

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

Сравним два варианта:

Вариант А (Медленный): ИЗ РегистрНакопления.Продажи.Обороты() КАК Продажи ГДЕ Продажи.Подразделение В (&Список) Вариант Б (Быстрый): ИЗ РегистрНакопления.Продажи.Обороты(,,, Подразделение В (&Список)) КАК Продажи

Во втором случае платформа передаст фильтр напрямую в SQL-запрос к итогам, что значительно ускорит формирование отчета, особенно если данных в базе много. Помните: правильная работа с типами данных и структурой запроса — залог стабильной работы вашей конфигурации.

← На главную