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