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