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