Почему запрос 1С ничего не возвращает при незаполненном параметре и как правильно настроить отбор

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

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

Разберем распространенную ошибку, с которой сталкиваются разработчики при попытке реализовать такую логику через конструкцию ВЫБОР в секции ГДЕ языка запросов, а также рассмотрим правильные подходы к решению этой задачи в коде BSL и Системе компоновки данных (СКД).

Причина ошибки: как работает ВЫБОР в секции ГДЕ без ветки ИНАЧЕ

Проанализируем исходный фрагмент запроса, вызывающий ошибку:


ГДЕ
    АР_РасходыПоСобственникам.Собственник = &ВыбСобственник
    И АР_РасходыПоСобственникам.Период МЕЖДУ &ВыбНач И &ВыбКон
    И ВЫБОР
        КОГДА НЕ &ВыбСтатьяРасходов = ЗНАЧЕНИЕ(Справочник.АР_ВидыРасходов.ПустаяСсылка)
            ТОГДА АР_РасходыПоСобственникам.СтатьяРасходов В ИЕРАРХИИ (&ВыбСтатьяРасходов)
    КОНЕЦ

Выясним, почему данное условие перестает выводить данные, когда параметр &ВыбСтатьяРасходов содержит пустую ссылку:

  1. Если параметр заполнен, условие КОГДА выполняется, и конструкция ВЫБОР возвращает результат проверки СтатьяРасходов В ИЕРАРХИИ (&ВыбСтатьяРасходов) — то есть ИСТИНА или ЛОЖЬ.
  2. Если параметр равен пустой ссылке, условие КОГДА НЕ ... возвращает значение ЛОЖЬ.
  3. Так как секция ИНАЧЕ в выражении ВЫБОР отсутствует, платформа (и СУБД) возвращает значение NULL.
  4. В секции ГДЕ логическое вычисление И NULL приравнивается к ЛОЖЬ. Из-за этого итоговое условие отбора не выполняется ни для одной строки таблицы, и выборка оказывается пустой.

Способ 1. Добавление ветки ИНАЧЕ ИСТИНА в текст запроса

Если условие пишется внутри конструкции ВЫБОР в тексте запроса, необходимо явно указать, что при незаполненном параметре выражение должно возвращать булево значение ИСТИНА.

Рассмотрим исправленный вариант условия:


ГДЕ
    АР_РасходыПоСобственникам.Собственник = &ВыбСобственник
    И АР_РасходыПоСобственникам.Период МЕЖДУ &ВыбНач И &ВыбКон
    И ВЫБОР
        КОГДА НЕ &ВыбСтатьяРасходов = ЗНАЧЕНИЕ(Справочник.АР_ВидыРасходов.ПустаяСсылка)
            ТОГДА АР_РасходыПоСобственникам.СтатьяРасходов В ИЕРАРХИИ (&ВыбСтатьяРасходов)
        ИНАЧЕ ИСТИНА
    КОНЕЦ

Важное замечание по производительности: Использование конструкции ВЫБОР в секции ГДЕ блокирует использование индексов СУБД по проверяемому полю. СУБД не может применить поиск по индексу и переходит к полному сканированию таблицы, что при больших объемах данных приводит к существенному замедлению работы отчета.

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

Если запрос выполняется в программном коде BSL (в модуле объекта или формы), наиболее правильным решением с точки зрения производительности является динамическое добавление строки условия в текст запроса только при наличии значения параметра.

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


ТекстЗапроса = 
"ВЫБРАТЬ
|	АР_РасходыПоСобственникам.Собственник КАК Собственник,
|	АР_РасходыПоСобственникам.СтатьяРасходов КАК СтатьяРасходов,
|	АР_РасходыПоСобственникам.Сумма КАК Сумма
|ИЗ
|	РегистрНакопления.АР_РасходыПоСобственникам КАК АР_РасходыПоСобственникам
|ГДЕ
|	АР_РасходыПоСобственникам.Собственник = &ВыбСобственник
|	И АР_РасходыПоСобственникам.Период МЕЖДУ &ВыбНач И &ВыбКон";

Если ЗначениеЗаполнено(Объект.ВыбСтатьяРасходов) Тогда
    ТекстЗапроса = ТекстЗапроса + "
    |	И АР_РасходыПоСобственникам.СтатьяРасходов В ИЕРАРХИИ (&ВыбСтатьяРасходов)";
КонецЕсли;

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

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

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

Способ 3. Использование необязательных условий в СКД

Если отчет разрабатывается в Системе компоновки данных (СКД), использовать сложные конструкции ВЫБОР в секции ГДЕ не требуется. Платформа 1С содержит встроенный механизм управления необязательными условиями.

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


ВЫБРАТЬ
	АР_РасходыПоСобственникам.Собственник КАК Собственник,
	АР_РасходыПоСобственникам.СтатьяРасходов КАК СтатьяРасходов,
	АР_РасходыПоСобственникам.Сумма КАК Сумма
ИЗ
	РегистрНакопления.АР_РасходыПоСобственникам КАК АР_РасходыПоСобственникам
ГДЕ
	АР_РасходыПоСобственникам.Собственник = &ВыбСобственник
	И АР_РасходыПоСобственникам.Период МЕЖДУ &ВыбНач И &ВыбКон
	{ГДЕ
	АР_РасходыПоСобственникам.СтатьяРасходов В ИЕРАРХИИ (&ВыбСтатьяРасходов)}

Разберем особенности работы фигурных скобок в СКД:

  1. Условие, заключенное в фигурные скобки {ГДЕ ...}, считается необязательным.
  2. Если параметр &ВыбСтатьяРасходов заполнен на компоновке и флаг использования параметра установлен, СКД автоматически включит условие в итоговый SQL-запрос.
  3. Если параметр не заполнен или снят флаг его использования, СКД полностью вырежет этот фрагмент из финального запроса, обеспечив максимальную скорость выполнения.
← На главную