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