Как рассчитать сумму максимальных значений в итогах отчета СКД 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов в Системе компоновки данных (СКД) на платформе 1С:Предприятие разработчики часто сталкиваются с необходимостью расчета сложных, нелинейных итогов. Типичный пример такой задачи — вывод информации о штатном расписании, окладах или ставках сотрудников. Из-за особенностей построения запросов (например, при соединении таблиц «один ко многим», когда к данным о сотруднике присоединяются детальные записи по начислениям, проектам или отработанным дням) строки в выборке могут дублироваться на уровне базы данных.

Если для ресурса КоличествоСтавок применить простую агрегатную функцию Сумма, СКД послушно сложит ставку сотрудника столько раз, сколько детальных строк по нему вывелось в отчет, что приведет к значительному завышению результата. Чтобы решить эту проблему на уровне детальных записей по сотруднику, разработчики часто используют функцию Максимум. На уровне конкретного сотрудника это дает абсолютно верный результат. Однако при расчете общих итогов по подразделению или по организации в целом стандартная функция Максимум выберет лишь наибольшую ставку среди всех сотрудников (например, покажет 1.0 вместо реальной суммы всех ставок сотрудников подразделения, равной 5.5). Выясним причину этого поведения и разберем по шагам, как настроить расчет суммы локальных максимумов с помощью механизма двойного агрегирования.

Решение проблемы: Двойное агрегирование через ВычислитьВыражениеСГруппировкойМассив

Для реализации корректного расчета нам понадобится настроить вкладку «Ресурсы» в схеме компоновки данных. Платформа 1С позволяет добавлять одно и то же поле в список ресурсов несколько раз, задавая индивидуальные правила расчета для каждого уровня группировки. Проанализируем, как настроить этот механизм.

Рассмотрим по шагам настройку ресурсов:

  1. Добавим поле КоличествоСтавок в список ресурсов первый раз. Это значение будет рассчитываться для детальной группировки по сотруднику. В поле «Выражение» укажем: Максимум(КоличествоСтавок). В колонке «Рассчитывать по...» выберем группировку Сотрудник.
  2. Добавим это же поле в ресурсы второй раз. Это выражение будет рассчитывать итоги по всем вышестоящим уровням группировки (например, по подразделениям и организации в целом). В поле «Выражение» пропишем следующую формулу двойного агрегирования:

Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(КоличествоСтавок)", "Сотрудник"))

В колонке «Рассчитывать по...» для этой второй строки ресурсов укажем группировки Подразделение и ОбщийИтог (или оставим это поле пустым, чтобы расчет применялся ко всем остальным группировкам по умолчанию, которые не настроены явно в других строках).

Как устроен этот механизм изнутри?

Давайте подробно разберем, как именно СКД обрабатывает написанное нами выражение. Функция ВычислитьВыражениеСГруппировкойМассив выполняет обход детальных записей в контексте текущей вышестоящей группировки (например, внутри конкретного подразделения). Для каждого уникального значения группировки Сотрудник внутри этого подразделения она вычисляет локальный максимум по формуле "Максимум(КоличествоСтавок)". Полученные промежуточные значения складываются во временный массив в оперативной памяти.

Затем внешняя функция Сумма производит сложение всех элементов этого полученного массива. Таким образом, мы получаем математически верную сумму ставок уникальных сотрудников, полностью избегая искажения итогов из-за дублирования строк в исходной выборке.

Важные подводные камни и нюансы использования метода

Хотя механизм двойного агрегирования чрезвычайно мощен, при его практическом использовании разработчики часто совершают типичные ошибки. Проанализируем основные подводные камни:

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

Альтернативный подход: Оптимизация на уровне запроса

В крупных информационных базах или при высоких требованиях к быстродействию лучшим решением будет перенос логики агрегирования непосредственно в текст запроса. Посмотрим на пример, как можно оптимизировать получение данных и отказаться от сложных вычислений в ресурсах СКД.

Для этого мы можем сначала сгруппировать данные по сотрудникам во временной таблице, избавившись от дублирования записей, а затем соединить результат с остальными аналитическими таблицами:


ВЫБРАТЬ
    СведенияОСтавках.Сотрудник КАК Сотрудник,
    МАКСИМУМ(СведенияОСтавках.КоличествоСтавок) КАК КоличествоСтавок
ПОМЕСТИТЬ ВТ_СтавкиСотрудников
ИЗ
    РегистрСведений.СведенияОСтавках КАК СведенияОСтавках
СГРУППИРОВАТЬ ПО
    СведенияОСтавках.Сотрудник;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_СтавкиСотрудников.Сотрудник КАК Сотрудник,
    ВТ_СтавкиСотрудников.КоличествоСтавок КАК КоличествоСтавок,
    Продажи.Подразделение КАК Подразделение,
    Продажи.СуммаОбороты КАК СуммаОбороты
ИЗ
    ВТ_СтавкиСотрудников КАК ВТ_СтавкиСотрудников
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты КАК Продажи
        ПО ВТ_СтавкиСотрудников.Сотрудник = Продажи.Сотрудник

При таком подходе поле КоличествоСтавок попадает в СКД уже очищенным от дублей на уровне СУБД. Нам больше не нужно прибегать к сложным функциям компоновщика — достаточно перетащить это поле в ресурсы схемы компоновки данных и назначить ему стандартную функцию Сумма(КоличествоСтавок) для всех уровней группировки. Это значительно ускорит выполнение отчета и сэкономит оперативную память сервера приложений.

← На главную