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