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