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