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