При разработке аналитических отчетов в системе компоновки данных (СКД) часто возникает задача расчета накопительных итогов. Типичный пример — ABC-анализ, где нам нужно не просто знать долю каждого товара в общей выручке, но и понимать кумулятивный (нарастающий) процент. Это позволяет быстро определить группу товаров, приносящую, например, 80% прибыли.
Многие начинающие разработчики пытаются реализовать это через вычисляемые поля или сложные запросы, однако в СКД существует мощный встроенный инструмент — функция ВычислитьВыражение(). В этой статье мы подробно разберем, как правильно использовать эту функцию для расчета долей и накопительных итогов.
Первое и самое важное правило, которое мы должны усвоить: расчеты, использующие контекст группировок (например, "предыдущая строка" или "общий итог по магазину"), должны описываться на закладке Ресурсы, а не в Вычисляемых полях. Проанализируем, почему это так.
Вычисляемые поля рассчитываются для каждой записи детальных данных еще до того, как система начнет группировать и агрегировать результаты. В них нельзя использовать агрегатные функции типа Сумма(), ориентированные на группировки. Ресурсы же рассчитываются в момент компоновки результата, когда иерархия строк уже определена. Именно на этом этапе функции СКД могут обращаться к значениям других строк в рамках одной группировки.
Прежде чем переходить к накопительному итогу, рассмотрим, как рассчитать обычную долю (процент) товара от общих продаж по магазину или складу. Допустим, у нас есть поле Ср_Нед_Продажи_Шт. Нам нужно разделить сумму продаж текущей строки на общую сумму продаж по всему магазину.
В поле "Выражение" на закладке "Ресурсы" мы укажем следующую формулу:
Сумма(Ср_Нед_Продажи_Шт) / ВычислитьВыражение("Сумма(Ср_Нед_Продажи_Шт)", "Магазин") * 100
Разберем этот пример. Первый параметр функции ВычислитьВыражение() — это само агрегатное выражение в кавычках. Второй параметр "Магазин" указывает системе, что сумму нужно считать не для текущей строки, а в контексте всей группировки Магазин. Таким образом, знаменатель будет одинаковым для всех товаров внутри одного магазина.
Теперь перейдем к основной задаче: как прибавить к доле текущего товара доли всех предыдущих товаров в списке? Рассмотрим ситуацию, когда товары отсортированы по убыванию продаж. Нам нужно, чтобы для второй строки результат был равен Доля1 + Доля2, для третьей — Доля1 + Доля2 + Доля3 и так далее.
Для этого воспользуемся расширенными параметрами функции ВычислитьВыражение(). Посмотрим на итоговую формулу для ресурса:
ВычислитьВыражение("Сумма(Ср_Нед_Продажи_Шт)", , , "Первая", "Текущая") / ВычислитьВыражение("Сумма(Ср_Нед_Продажи_Шт)", "Магазин") * 100
Давайте проанализируем, что означают эти параметры:
Благодаря связке "Первая" и "Текущая", СКД на каждой строке отчета будет "пробегать" по всем записям от начала до текущей позиции и складывать их значения. Это и дает нам искомый накопительный итог.
При расчете накопительной доли критически важен порядок строк. Если отчет в СКД отсортирован пользователем по наименованию, а вы хотите считать накопительный итог по сумме продаж, возникнет логическое несоответствие. Чтобы расчет был корректным независимо от настроек пользователя, рекомендуется явно указывать сортировку внутри функции.
Например, если мы хотим считать накопительную сумму строго по убыванию продаж, формула может выглядеть так:
ВычислитьВыражение("Сумма(Продажи) УБЫВ", , , "Первая", "Текущая")
Важный технический момент: Ключевое слово УБЫВ или ВОЗР пишется внутри кавычек первого параметра. Если написать его снаружи, система выдаст ошибку синтаксиса (как это часто случается при разработке сложных условий ВЫБОР).
В реальных отчетах часто встречаются ситуации, когда продажи за период равны нулю (например, новый магазин или товар, выведенный из ассортимента). Чтобы отчет не "падал" с ошибкой деления на ноль, мы должны обернуть нашу формулу в проверку. Проанализируем безопасный вариант выражения для ресурса:
ВЫБОР
КОГДА ВычислитьВыражение("Сумма(Ср_Нед_Продажи_Шт)", "Магазин") = 0
ТОГДА 0
ИНАЧЕ ВычислитьВыражение("Сумма(Ср_Нед_Продажи_Шт)", , , "Первая", "Текущая") / ВычислитьВыражение("Сумма(Ср_Нед_Продажи_Шт)", "Магазин") * 100
КОНЕЦ
Этот подход гарантирует стабильную работу отчета даже при отсутствии данных в определенных группировках.
Функция ВычислитьВыражение() полезна не только для накопления. С ее помощью можно сравнивать текущую строку с предыдущей. Рассмотрим пример расчета отклонения продаж текущего месяца от предыдущего:
(Сумма(Продажи) - ВычислитьВыражение("Сумма(Продажи)", , , "Предыдущая", "Предыдущая")) / ВычислитьВыражение("Сумма(Продажи)", , , "Предыдущая", "Предыдущая") * 100
Здесь мы используем параметры "Предыдущая", "Предыдущая", чтобы получить значение ресурса ровно из одной предшествующей строки. Это позволяет создавать динамические аналитические отчеты без модификации запроса в базе данных.
Таким образом, использование ВычислитьВыражение() позволяет перенести сложную аналитическую логику из кода 1С или тяжелых SQL-запросов непосредственно в настройки системы компоновки данных, что значительно упрощает поддержку и развитие отчетов.