Как реализовать расчет нарастающего итога по поездкам вагонов на каждую дату в СКД

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

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

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

Метод 1. Реализация нарастающего итога через запрос (Самосоединение)

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

Рассмотрим по шагам, как составить такой запрос:

  1. Выберем основные данные из регистра сведений во временную таблицу. Назовем ее ВТ_Данные.
  2. Выполним левое соединение ВТ_Данные (как Т1) с этой же таблицей ВТ_Данные (как Т2).
  3. Установим условие связи: Т1.Вагон = Т2.Вагон И Т1.Период >= Т2.Период.
  4. Сгруппируем результат по всем полям таблицы Т1, а для полей таблицы Т2 применим агрегатную функцию СУММА или КОЛИЧЕСТВО.

Посмотрим на пример кода такого запроса:


ВЫБРАТЬ
    Рег.Вагон КАК Вагон,
    Рег.Период КАК Период,
    1 КАК КоличествоПоездок
ПОМЕСТИТЬ ВТ_Ходки
ИЗ
    РегистрСведений.ДвиженияВагонов КАК Рег
ГДЕ
    Рег.Период МЕЖДУ &НачалоПериода И &КонецПериода;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Т1.Вагон КАК Вагон,
    Т1.Период КАК Период,
    СУММА(Т2.КоличествоПоездок) КАК НомерХодкиНаДату
ИЗ
    ВТ_Ходки КАК Т1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Ходки КАК Т2
        ПО Т1.Вагон = Т2.Вагон
            И Т1.Период >= Т2.Период
ГРУППИРОВАТЬ ПО
    Т1.Вагон,
    Т1.Период

Важный нюанс: Если в одну и ту же секунду (период) у одного вагона может быть несколько записей, условие Т1.Период >= Т2.Период выдаст неверный результат (дублирование сумм). В этом случае в соединение нужно добавить уникальный идентификатор записи или дополнительное поле (например, номер строки или более точное время).

Метод 2. Использование функции СКД ВычислитьВыражение

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

Рассмотрим подробнее синтаксис для нарастающего итога:

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

Чтобы расчет корректно "сбрасывался" при переходе от одного вагона к другому, необходимо правильно настроить область расчета. Разберем алгоритм настройки:

  1. Добавим в СКД вычисляемое поле (например, НарастающийИтог).
  2. Перейдем на вкладку Ресурсы.
  3. В поле "Выражение" для нашего ресурса пропишем:

ВычислитьВыражение("Сумма(КоличествоПогрузок)", "Вагон", "Группировка", "Первая", "Текущая")
  1. В колонке Рассчитывать по... укажите группировку, которая находится ниже вагона (например, Период или ДетальныеЗаписи). Это критически важно: если рассчитывать это выражение по группировке "Вагон", система выдаст общий итог, а не нарастающий.

Проанализируем параметры функции:

Метод 3. Связь наборов данных с условием (Dataset Links)

Этот метод считается наиболее гибким, когда нужно считать данные "с начала времен", а не только за период отчета. Например, отчет формируется за квартал, но нам нужно знать, сколько раз вагон ходил вообще, начиная с 2019 года.

Разберем, как это реализовать:

  1. Создадим НаборДанных1 (Запрос): выбирает все поездки вагона за нужный период (из параметров СКД).
  2. Создадим НаборДанных2 (Запрос): выбирает абсолютно все записи из регистра сведений по всем вагонам без ограничения по периоду (или с ограничением "с начала времен").
  3. На вкладке Связи наборов данных укажем:
    • Источник связи: НаборДанных1.
    • Приемник связи: НаборДанных2.
    • Условие связи: Вагон = Вагон.
    • Параметры: добавьте условие, что Период из второго набора должен быть меньше или равен Периоду из первого набора.

В этом случае для каждой строки первого набора СКД выполнит отдельный подзапрос (или оптимизированную выборку) ко второму набору, передав туда текущую дату как фильтр "СВЕРХУ". В результате мы получим точное количество ходок на конкретный момент времени без сложных JOIN в основном запросе.

Метод 4. Особенности расчета среднего значения

Иногда задача усложняется: нужно не просто посчитать количество, а вычислить "среднее количество погрузок в день на текущую дату". Здесь обычного суммирования недостаточно. Выясним причину: если за один день было 3 погрузки, среднее по записям и среднее по дням — это разные вещи.

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

Пример выражения для среднего значения нарастающим итогом:


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

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

Оптимизация и "пустые" периоды

Проанализируем ситуацию, когда вагон не ходил в определенные дни, но нам нужно протащить нарастающий итог через эти даты. Если просто выбрать данные из регистра, дат, когда не было движений, в отчете не будет.

Чтобы решить эту проблему, используем механизм дополнения периодов:

  1. В настройках группировки по полю Период перейдите к настройкам иерархии и выберите "Дополнять периоды".
  2. Укажите тип дополнения (День, Месяц и т.д.).
  3. Функция ВычислитьВыражение (Метод 2) автоматически заполнит "пустые" строки значениями из предыдущих периодов, так как для них граница "Текущая" будет включать последнее известное значение.

Заключение: Для простых отчетов с небольшим объемом данных лучше использовать Метод 2 (ресурсные функции), так как это сохраняет запрос читаемым. Если же требуется высокая производительность при расчете огромных массивов данных (сотни тысяч вагонов), рекомендуется Метод 1 (запрос) с предварительной индексацией временных таблиц по полям Вагон и Период.

← На главную