В процессе разработки отчетов в Системе компоновки данных (СКД) часто возникает задача, которая ставит в тупик даже опытных разработчиков: как посчитать количество уникальных записей по условию, которое само основано на агрегированной величине? Классический пример — найти количество клиентов, сумма продаж по которым за период превысила заданный порог.
Проанализируем типичную ситуацию. У нас есть отчет по продажам с полями Менеджер, Партнер, Заказ, СуммаВыручки. Нам нужно вывести в итогах отчета общее количество партнеров, у которых сумма выручки за период, например, больше или равна 100 000 рублей.
Интуитивная попытка решить это "в лоб" в вычисляемом поле ресурса выглядит так:
ВЫБОР
КОГДА Сумма(СуммаВыручки) >= 100000
ТОГДА Количество(РАЗЛИЧНЫЕ Партнер)
КОНЕЦ
Однако такой подход не работает и приводит к некорректным, завышенным результатам. Причина кроется в том, что СКД не допускает прямого использования вложенных агрегатных функций. Здесь мы пытаемся применить агрегатную функцию Количество() внутри условия, которое уже содержит другую агрегатную функцию Сумма(). СКД выполняет агрегацию в один проход, и такая логика нарушает этот принцип.
Давайте разберем два правильных и эффективных способа решения этой задачи.
Этот метод считается классическим и наиболее производительным, поскольку вся сложная логика отбора данных переносится на уровень базы данных (СУБД), которая для таких задач и предназначена. Суть метода — подготовить набор данных, который уже содержит только нужных нам партнеров, и затем в основном запросе просто посчитать их количество.
Разберем по шагам:
Партнер и считаем для каждого из них общую сумму выручки.ИМЕЮЩИЕ (аналог ГДЕ, но для агрегированных данных) мы отфильтровываем результат, оставляя только тех партнеров, у которых итоговая сумма выручки удовлетворяет нашему условию (>= 100000).Посмотрим на примерную структуру запроса. Допустим, у нас есть регистр накопления Продажи.
ВЫБРАТЬ
ПродажиОтфильтрованные.Партнер,
ПродажиОтфильтрованные.СуммаВыручки,
// Другие поля из основного набора данных
ИЗ
(ВЫБРАТЬ
ПродажиОбороты.Партнер КАК Партнер,
СУММА(ПродажиОбороты.СуммаВыручки) КАК СуммаВыручки
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты
СГРУППИРОВАТЬ ПО
ПродажиОбороты.Партнер
ИМЕЮЩИЕ
СУММА(ПродажиОбороты.СуммаВыручки) >= 100000) КАК ПродажиОтфильтрованные
// Здесь можно соединить с другими таблицами для получения остальных полей отчета
// ...
Теперь в ресурсах отчета достаточно будет указать простое выражение: Количество(Различные Партнер). Оно будет применено к уже отфильтрованному набору данных и даст корректный результат.
Преимущества:
Недостатки:
Это более гибкий и современный способ, который позволяет реализовать сложную логику непосредственно в настройках отчета, не затрагивая основной запрос. Он идеально подходит, когда нужно добавить подобный расчет в уже существующий отчет "на лету".
В этом методе мы используем мощную функцию СКД ВычислитьВыражениеСГруппировкойМассив(). Разберем, как она работает.
Для поля-ресурса, которое должно считать наших партнеров, нужно написать следующее выражение:
Сумма(ВычислитьВыражениеСГруппировкойМассив("ВЫБОР КОГДА Сумма(СуммаВыручки) >= 100000 ТОГДА 1 ИНАЧЕ 0 КОНЕЦ", "Партнер"))
Давайте проанализируем эту конструкцию изнутри наружу:
"ВЫБОР КОГДА Сумма(СуммаВыручки) >= 100000 ТОГДА 1 ИНАЧЕ 0 КОНЕЦ" — это выражение, которое мы хотим вычислить. Обратите внимание, оно записано как строка."Партнер" — это строка с именем группировки, в контексте которой будет вычисляться первое выражение. СКД сгруппирует все записи по партнерам.ВычислитьВыражениеСГруппировкойМассив(...) — эта функция делает "магию". Она выполняет следующие действия:
Партнер.1. Если меньше — 0.Сумма(...) — это внешняя, обычная агрегатная функция. Она применяется к результату работы внутренней функции, то есть к массиву. Она просто суммирует все элементы массива (1 + 0 + 0 + 1 + 1 + ...), и в итоге мы получаем общее количество партнеров, для которых условие выполнилось.Этот метод элегантен, так как позволяет обойти ограничение на вложенные агрегаты, выполняя агрегацию в два этапа: сначала внутри функции для каждой группы, а затем снаружи над результатом.
Преимущества:
Недостатки:
Мы рассмотрели два мощных способа решения задачи подсчета по агрегатному условию. Выбор между ними зависит от ваших приоритетов:
ИМЕЮЩИЕ.ВычислитьВыражениеСГруппировкойМассив.Оба подхода являются штатными и правильными инструментами СКД, и знание их обоих позволит вам эффективно решать самые нетривиальные задачи при построении аналитической отчетности в 1С.