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