Как в СКД просуммировать номера строк и получить корректный общий итог?

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

При разработке отчетов на базе системы компоновки данных (СКД) часто возникает задача вывести порядковый номер строки и в подвале отчета получить сумму этих номеров. На первый взгляд решение кажется очевидным: добавить вычисляемое поле для нумерации и вынести его в ресурсы с агрегатной функцией Сумма. Однако на практике разработчики сталкиваются с тем, что вместо ожидаемой суммы чисел от 1 до N система возвращает совершенно иное, завышенное значение. Разберем эту ситуацию, выясним причину такого поведения платформы и подробно рассмотрим варианты получения правильного результата.

В чем причина некорректного подсчета суммы номеров?

Проанализируем типовую ситуацию. Предположим, у нас есть набор данных с 12 записями. Для нумерации строк создается вычисляемое поле НомерСтроки со следующим выражением нарастающего итога:

ВычислитьВыражение("Сумма(1)", , , "Первая", "Текущая")

На уровне детальных записей такое выражение работает отлично: в каждой строке выводится ее порядковый номер от 1 до 12. Проблема появляется при попытке просуммировать это поле в ресурсах стандартной конструкцией Сумма(НомерСтроки). В итоге вместо ожидаемого значения 78 (так как 1 + 2 + ... + 12 = 78) отчет выводит 144.

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

Стандартные системные поля (например, СистемныеПоля.НомерПоПорядку) также не решают проблему, поскольку они служат исключительно для оформления вывода и не могут быть агрегированы как полноценные числовые ресурсы. Рассмотрим рабочие способы решения этой задачи.

Способ 1. Использование формулы суммы арифметической прогрессии в ресурсах

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

S = N * (N + 1) / 2

Так как общее количество строк в группировке можно легко получить стандартными функциями СКД, применим эту формулу непосредственно на вкладке Ресурсы.

Разберем по шагам настройку схемы компоновки данных:

  1. На вкладке Вычисляемые поля оставляем поле НомерСтроки с выражением:
    ВычислитьВыражение("Сумма(1)", , , "Первая", "Текущая")
  2. Переходим на вкладку Ресурсы и настраиваем расчет поля раздельно для строк и общих итогов. Для этого добавляем поле НомерСтроки дважды.
  3. Для первой строки ресурса в колонке Рассчитывать по... выбираем детальные записи (или группировку строк) и задаем выражение:
    НомерСтроки
  4. Для второй строки ресурса оставляем поле Рассчитывать по... пустым (что соответствует общим итогам) или указываем группировку ОбщийИтог, а в колонке Выражение указываем формулу прогрессии:
    Количество() * (Количество() + 1) / 2
    или через агрегат единиц:
    Сумма(1) * (Сумма(1) + 1) / 2

Посмотрим на результат: в детальных записях выводятся значения от 1 до 12, а в строке общего итога СКД производит расчет: 12 * (12 + 1) / 2 = 78. Задача решена без перегрузки процессора компоновки.

Способ 2. Двойная агрегация через массив группировки

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

Разберем настройку вкладки Ресурсы:

  1. Для поля НомерСтроки при расчете по группировке детальных записей оставляем значение:
    НомерСтроки
  2. В строке расчета по общим итогам указываем составное выражение агрегации по массиву:
    Сумма(ВычислитьВыражениеСГруппировкойМассив("НомерСтроки", "Числа"))
    (где "Числа" — имя поля группировки детальных записей отчета).

Проанализируем работу этой конструкции: функция собирает массив вычисленных номеров строк [1, 2, 3, ..., 12], после чего внешняя функция Сумма складывает элементы полученного массива, возвращая искомое число 78.

Способ 3. Нумерация строк на уровне запроса

Если нумерация требуется не только для визуализации, но и должна участвовать в сложных кросс-табличных расчетах, целесообразно сформировать номер строки заранее в тексте запроса набора данных. В таком случае номер становится обычным числовым полем выборки, и к нему можно применять стандартную агрегацию Сумма(НомерСтроки) без дополнительных условий.

Посмотрим на пример формирования номеров строк в тексте запроса с помощью соединения таблицы самой с собой:


ВЫБРАТЬ
    ИсходныеДанные.Число КАК Число
ПОМЕСТИТЬ ВТ_Данные
ИЗ
    &ТаблицаЧисел КАК ИсходныеДанные
;

ВЫБРАТЬ
    Т1.Число КАК Число,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Т2.Число) КАК НомерСтроки
ИЗ
    ВТ_Данные КАК Т1
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2
        ПО Т1.Число >= Т2.Число
СГРУППИРОВАТЬ ПО
    Т1.Число

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

← На главную