При разработке отчетов на Системе компоновки данных (СКД) часто возникает задача предоставить пользователю возможность простой фильтрации по сложным правилам. Например, когда нужно вывести в отчет товары (которые не являются услугами) или услуги, но только те, по которым есть оформленные заказы. В виде логической формулы это условие выглядит следующим образом: (Не Услуга) ИЛИ (Услуга И Заказ > 0).
Стандартный интерфейс быстрых настроек СКД по умолчанию предлагает плоский список условий, соединяемых по логическому «И». В этой статье мы подробно разберем, как объединить условия в группы «ИЛИ» и «И», как правильно вывести их в пользовательские настройки и как решить эту задачу программным путем.
Самый простой и правильный с точки зрения архитектуры 1С способ — настроить структуру отбора непосредственно в схеме компоновки данных. Разберем этот процесс по шагам.
Услуга со значением Ложь (это покроет часть условия «Не Услуга»).Услуга со значением Истина.Заказ с видом сравнения Больше и значением 0.Теперь структура нашего отбора полностью соответствует требуемой логике. Однако, если оставить настройки в таком виде, пользователь не увидит их на форме отчета в качестве быстрого отбора. Нам нужно правильно настроить их отображение.
Чтобы составной отбор стал доступен пользователю в шапке отчета, выполним следующие действия:
Товары и заказанные услуги.После запуска отчета в режиме «1С:Предприятие» пользователь увидит в шапке простую и понятную галочку «Товары и заказанные услуги». При ее включении система автоматически применит всю настроенную нами структуру вложенных отборов.
Если структура отборов становится слишком запутанной или требуется часто менять условия, построение сложных деревьев групп в интерфейсе может усложнить поддержку отчета. В таких ситуациях отличной альтернативой является использование Вычисляемых полей в СКД.
Рассмотрим, как перенести логику составного условия на уровень расчета полей:
ДоступноДляЗаказа) и заголовок (например, Доступно для заказа (Товары или Услуги с заказом)).
ВЫБОР
КОГДА НЕ Услуга ТОГДА Истина
КОГДА Услуга И Заказ > 0 ТОГДА Истина
ИНАЧЕ Ложь
КОНЕЦ
Булево.ДоступноДляЗаказа равно Истина.Этот способ существенно упрощает UX (пользовательский опыт). Вместо работы со сложной иерархией групп отбора СУБД, пользователь взаимодействует с простым флагом типа «Да/Нет». Разработчику при этом гораздо проще контролировать логику в одном месте — в выражении вычисляемого поля.
В некоторых случаях составные условия необходимо формировать динамически, в зависимости от действий пользователя на форме или других внешних условий. Для этого используется программная работа с компоновщиком настроек СКД.
Проанализируем пример кода, который позволяет программно создать группу «ИЛИ», вложенные группы «И» и заполнить их элементами отбора. Данный код можно разместить в модуле формы отчета или в общем модуле при инициализации компоновщика настроек:
// Получаем коллекцию элементов отбора из компоновщика настроек (например, из фиксированных настроек)
СписокОтборФикс = КомпоновщикНастроек.ФиксированныеНастройки.Отбор;
// 1. Создаем общую родительскую группу "И" для объединения всех условий отчета
ОтборГруппаОбщая = СписокОтборФикс.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ОтборГруппаОбщая.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
ОтборГруппаОбщая.Использование = Истина;
ОтборГруппаОбщая.Представление = "Общий фильтр по доступности";
// 2. Создаем группу "ИЛИ" для нашего составного условия
ОтборГруппаИЛИ = ОтборГруппаОбщая.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ОтборГруппаИЛИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИЛИ;
ОтборГруппаИЛИ.Использование = Истина;
// 3. Добавляем первое простое условие в группу "ИЛИ" - (Не Услуга)
НовыйЭлемент1 = ОтборГруппаИЛИ.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйЭлемент1.ЛевоеЗначение = Новый ИсточникДоступныхНастроекКомпоновкиДанных.ПолеКомпоновкиДанных("Услуга");
НовыйЭлемент1.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
НовыйЭлемент1.ПравоеЗначение = Ложь;
НовыйЭлемент1.Использование = Истина;
// 4. Создаем вложенную группу "И" внутри группы "ИЛИ" для связки (Услуга И Заказ > 0)
ОтборГруппаВложеннаяИ = ОтборГруппаИЛИ.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ОтборГруппаВложеннаяИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
ОтборГруппаВложеннаяИ.Использование = Истина;
// 5. Добавляем элементы во вложенную группу "И"
// Условие: Услуга = Истина
НовыйЭлемент2 = ОтборГруппаВложеннаяИ.Элементы.Добавить(Tip("ЭлементОтбораКомпоновкиДанных"));
НовыйЭлемент2.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Услуга");
НовыйЭлемент2.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
НовыйЭлемент2.ПравоеЗначение = Истина;
НовыйЭлемент2.Использование = Истина;
// Условие: Заказ > 0
НовыйЭлемент3 = ОтборГруппаВложеннаяИ.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйЭлемент3.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Заказ");
НовыйЭлемент3.ВидСравнения = ВидСравненияКомпоновкиДанных.Больше;
НовыйЭлемент3.ПравоеЗначение = 0;
НовыйЭлемент3.Использование = Истина;
При программном управлении отборами важно помнить: если вы хотите, чтобы эти настройки появились в пользовательском интерфейсе (в быстрых настройках), их нужно добавлять не в коллекцию ФиксированныеНастройки, а непосредственно в коллекцию пользовательских настроек:
КомпоновщикНастроек.ПользовательскиеНастройки.Элементы
Для корректной привязки программно созданных элементов к пользовательскому интерфейсу им необходимо сопоставлять уникальный идентификатор ИдентификаторПользовательскойНастройки, который должен быть зарегистрирован в схеме компоновки.
При проектировании сложных отчетов по крупным информационным базам (содержащим миллионы записей) крайне важно учитывать особенности работы СУБД с оператором ИЛИ.
Когда СУБД встречает в запросе условие ГДЕ (НЕ Услуга) ИЛИ (Услуга И Заказ > 0), планировщик запросов во многих случаях отказывается от использования индексов (происходит так называемый Index Scan вместо оптимального Index Seek). Это связано с тем, что индекс по полю Услуга не может эффективно отфильтровать данные при наличии альтернативной ветки логики.
Если вы заметили, что отчет после добавления составного отбора стал выполняться значительно дольше, рекомендуется оптимизировать структуру запроса в СКД следующими методами:
ОБЪЕДИНИТЬ ВСЕ для раздельного выбора данных (в первой части выбираем все товары, во второй — услуги с заказами), а затем накладывать более простые плоские отборы на результирующий набор данных.