Как настроить отбор по сложному ресурсу в СКД, если стандартные фильтры не работают?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Разберем детально, почему так происходит и какие существуют методики решения этой задачи, чтобы ваш отчет не только правильно считал данные, но и позволял пользователю фильтровать результат, например, по условию "Рентабельность <= 3%".

Анализ проблемы: почему СКД «игнорирует» отбор?

Прежде всего, нам необходимо понять внутреннюю логику работы процессора компоновки. Когда мы накладываем отбор на обычное поле, СКД старается включить это условие непосредственно в SQL-запрос (в секцию ГДЕ или ИМЕЮЩИЕ). Однако, когда формула ресурса содержит функции семейства ВычислитьВыражение, расчет происходит уже в оперативной памяти после того, как основные данные получены из базы.

Проанализируем ситуацию: если в формуле используется массив (результат функции ВычислитьВыражениеСГруппировкойМассив), система не может транслировать это в понятный базе данных запрос. В итоге отбор либо применяется к «пустым» значениям, либо полностью игнорируется, выдавая неадекватный результат (например, выводятся только строки с нулевой рентабельностью).

Решение 1: Перенос логики в вычисляемые поля

Один из наиболее эффективных способов — это разделение этапа вычисления и этапа агрегации. Рассмотрим, как это можно реализовать шаг за шагом:

  1. Перенесите сложную формулу расчета из закладки Ресурсы в закладку Вычисляемые поля.
  2. В поле Выражение на закладке Вычисляемые поля опишите логику расчета для детальных записей, если это возможно.
  3. На закладке Ресурсы в поле Выражение укажите простую агрегатную функцию над этим вычисляемым полем (например, Сумма(ИмяВычисляемогоПоля)).

Важный нюанс: если вам нужно рассчитывать агрегат от агрегата, используйте вложенные конструкции в ресурсах. Пример корректной записи для суммы по массиву вычислений:


Сумма(ВычислитьВыражениеСГруппировкойМассив("Сумма(ВаловаяПрибыль)", "Соглашение"))

Такой подход помогает СКД корректно определить тип возвращаемого значения и подготовить структуру данных для наложения фильтров.

Решение 2: Использование вспомогательного «Булева» ресурса для фильтрации

Если математическая сложность ресурса слишком высока и стандартный числовой отбор не срабатывает, мы можем применить хитрость с логическим флагом. Рассмотрим алгоритм:

  1. Создадим новый ресурс, назовем его СоответствуетКритериюРентабельности.
  2. В выражении ресурса пропишем условие, которое нас интересует. Например:
    
    Выбор 
        Когда (Сумма(Выручка) <> 0 И (Сумма(ВаловаяПрибыль) / Сумма(Выручка) * 100) <= &ПорогРентабельности) 
        Тогда Истина 
        Иначе Ложь 
    Конец
    
  3. В настройках отчета (вкладка «Отбор») установим фильтр: СоответствуетКритериюРентабельности Равно Истина.

Процессору компоновки гораздо проще обработать булево значение на этапе формирования итогов, чем пытаться сравнить результат динамического вычисления массива с числом.

Решение 3: Реализация через набор данных «Объект» (Таблица значений)

Если отчет работает слишком медленно или формулы настолько «навороченные», что СКД не справляется, наиболее надежным (хотя и более трудозатратным) методом будет использование Набора данных - объект. Разберем этот метод по шагам:

1. В модуле отчета программно сформируйте запрос, который получает все необходимые базовые данные.

2. Выгрузите результат запроса в ТаблицаЗначений.

3. Пройдите циклом по таблице или воспользуйтесь методом ЗаполнитьЗначения() для расчета рентабельности на уровне строк и итогов именно так, как требует бизнес-логика. На этом этапе вы можете использовать любые сложные алгоритмы 1С, которые недоступны в языке запросов или формулах СКД.

4. Передайте готовую таблицу в СКД:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    
    // Получаем данные
    ТаблицаДанных = ПолучитьТаблицуДляОтчета(); // Ваша функция расчета
    
    ВнешниеНаборыДанных = Новый Структура;
    ВнешниеНаборыДанных.Вставить("ТаблицаРентабельности", ТаблицаДанных);
    
    // Инициализируем компоновку
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры

Поскольку в СКД данные попадут уже в виде готовых чисел в колонке Рентабельность, стандартный отбор будет работать мгновенно и безошибочно, так как для системы это станет простым полем с типом Число.

Дополнительные советы по оптимизации

Проанализируем еще несколько важных моментов, которые могут влиять на работу отборов:

Выяснив причину неработоспособности отборов, мы видим, что проблема чаще всего кроется в попытке заставить СКД делать невозможное в рамках одного SQL-запроса. Использование вычисляемых полей или объектных наборов данных позволяет обойти эти ограничения, сохраняя гибкость и мощь Системы компоновки данных.

← На главную