При разработке отчетов в Системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда необходимо не просто вывести данные из базы, а произвести над ними арифметические операции, например, вычесть одну сумму из другой. На первый взгляд задача кажется тривиальной, однако при добавлении группировок или необходимости сохранить детальные записи для расшифровки, итоги могут начать «удваиваться» или рассчитываться некорректно. В этой статье мы подробно разберем, как правильно реализовать вычитание сумм и настроить ресурсы так, чтобы отчет оставался информативным и точным.
Рассмотрим ситуацию, когда в наборе данных у нас есть два показателя, например, СуммаПрихода и СуммаРасхода. Нам нужно получить их разность. Если мы просто выведем эти поля в детальных записях, проблем не возникнет. Однако, как только мы добавляем группировку по Документу или общие итоги, СКД начинает агрегировать данные. Если формула прописана только на уровне настроек отчета, система может сначала сложить все приходы, затем все расходы, и только в самом конце вычесть их, что не всегда соответствует бизнес-логике, особенно если нужно видеть разность по каждой строке отдельно.
Проанализируем ситуацию, описанную пользователем: при наличии группировки по полю Документ (Док) сумма рассчитывалась неверно. После удаления группировки итог стал правильным, но пропала возможность «провалиться» в документ (расшифровка). Выясним, как оставить документ в отчете и при этом получить верные цифры.
Один из самых быстрых способов решить проблему, когда детальные записи (документы) «ломают» общую сумму, — это изменить функцию агрегации в настройках ресурсов. По умолчанию СКД предлагает функцию Сумма(). Если данные в строках дублируются из-за особенностей соединения таблиц в запросе, использование Сумма приведет к завышению итогов.
Разберем по шагам, как применить функцию Максимум:
Сумма(ИмяПоля) пропишем Максимум(ИмяПоля).Важно: этот метод эффективен, когда по одному документу в выборку попадает несколько идентичных строк, которые не должны увеличивать итоговый показатель. Однако для полноценного расчета разности лучше использовать вычисляемые поля.
Для того чтобы расчет разности был максимально стабильным, мы рекомендуем создавать Вычисляемое поле. Это позволяет подготовить данные еще до того, как они попадут в механизм расчета итогов.
Проанализируем правильное выражение для вычисляемого поля. Часто при вычитании возникают ошибки, если одно из значений не заполнено (имеет значение NULL). В языке выражений СКД операция Число - NULL всегда дает NULL. Чтобы этого избежать, обязательно используем функцию ЕстьNULL.
Рассмотрим пример выражения в вычисляемом поле:
ЕстьNULL(СуммаНачальныйОстаток, 0) - ЕстьNULL(СуммаРасход, 0)
После создания такого поля на закладке Вычисляемые поля, его необходимо добавить на закладку Ресурсы. Там для него можно указать стандартное выражение Сумма(ВашеВычисляемоеПоле). Теперь СКД будет сначала вычислять разность для каждой строки, а затем корректно складывать эти разности в итогах по группировкам.
Если нам нужно сохранить расшифровку по документам, но при этом расчет итогов по иерархии должен идти по особому алгоритму, мы можем настроить колонку «Рассчитывать по...» на закладке Ресурсы.
Посмотрим на пример настройки:
Разность создаем две записи.Сумма(Разность) и в колонке «Рассчитывать по...» оставляем пустые значения (это будет расчет для всех уровней).В более сложных случаях, когда нужно вычесть значение из одной группировки из значения другой, или обратиться к итогам вышестоящего уровня, не удаляя текущую детализацию, мы используем мощную функцию ВычислитьВыражение. Рассмотрим пример, как можно получить сумму общего итога в каждой строке детальных записей, чтобы вычислить долю или разность:
Сумма(СуммаОборот) - ВычислитьВыражение("Сумма(СуммаОборот)", "ОбщийИтог")
Этот метод позволяет оставить поле Документ в структуре отчета. Система сначала рассчитает общую сумму по всему отчету, а затем позволит использовать это значение в математических операциях на уровне каждой строки с документом.
Если ваши суммы являются остатками (начальными или конечными), обычное суммирование через Сумма() в ресурсах приведет к логической ошибке (остатки по времени складывать нельзя). В этом случае проанализируем настройки на закладке Наборы данных:
При правильной настройке ролей СКД сама поймет, что при группировке по документам нужно показывать значение на момент документа, а в общих итогах — не складывать их за весь период, а выводить актуальный срез.
Таким образом, мы рассмотрели несколько вариантов решения задачи. Выбор конкретного метода зависит от того, насколько сложная структура вашего запроса. Для простых случаев достаточно функции Максимум или ЕстьNULL в вычисляемых полях. Для сложных аналитических отчетов с сохранением детальной расшифровки лучше комбинировать настройки ресурсов и функции вычисления выражений в контексте группировок.