Как просуммировать числовые показатели по максимальной дате внутри группировки?

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

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

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

Способ 1. Использование временных таблиц в запросе

Этот метод считается наиболее надежным и производительным, так как основная нагрузка ложится на СУБД. Проанализируем логику «двойного прохода» по данным.

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

Посмотрим на пример кода запроса, который реализует этот алгоритм:


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

////////////////////////////////////////////////////////////////////////////////
// Шаг 2 и 3: Соединяем и суммируем
ВЫБРАТЬ
    Т.Реквизит КАК Реквизит,
    СУММА(Т.ЧисловойРеквизит) КАК СуммаПоМаксДате
ИЗ
    &ТаблицаДанных КАК Т
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_МаксимальныеДаты КАК ВТ_Макс
        ПО Т.Реквизит = ВТ_Макс.Реквизит
        И Т.Дата = ВТ_Макс.МаксДата
СГРУППИРОВАТЬ ПО
    Т.Реквизит

Способ 2. Использование функций СКД в ресурсах

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

В настройках системы компоновки данных на закладке «Ресурсы» можно прописать выражение, которое будет анализировать записи в контексте группировки. Если данные внутри группировки отсортированы по дате, мы можем использовать конструкцию получения последней записи.

Рассмотрим выражение для ресурса:

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

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

Способ 3. Расширенная агрегация через ВычислитьВыражениеСГруппировкойМассив

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

Пример логики выражения:

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

Этот подход позволяет гибко управлять расчетами, не перегружая текст запроса условиями соединений, что особенно удобно, если структура группировок в отчете может меняться пользователем в режиме 1С:Предприятие.

Проблема неуникальных дат и ее решение

Рассмотрим ситуацию, которую часто упускают начинающие разработчики: что если в одной группе (по одному реквизиту) существуют две записи с абсолютно одинаковой максимальной датой? В этом случае стандартное соединение по дате выберет обе записи, и функция СУММА удвоит результат, что приведет к ошибке в отчете.

Для исключения дублирования рекомендуем использовать дополнительные критерии уникальности:

  1. Момент времени: Если данные берутся из документов, лучше использовать МоментВремени вместо Дата.
  2. Уникальный идентификатор: В запросе при поиске максимума можно выбирать МАКСИМУМ(Ссылка) (для ссылочных типов) или другой уникальный ключ в дополнение к дате.

Пример корректировки запроса для обеспечения уникальности:


ВЫБРАТЬ
    Т.Реквизит,
    МАКСИМУМ(Т.Дата) КАК МаксДата
ПОМЕСТИТЬ ВТ_Предварительная
ИЗ
    &ТаблицаДанных КАК Т
СГРУППИРОВАТЬ ПО
    Т.Реквизит;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Т.Реквизит,
    Т.МаксДата,
    МАКСИМУМ(Т.Ссылка) КАК МаксСсылка
ПОМЕСТИТЬ ВТ_ФинальныеКлючи
ИЗ
    &ТаблицаДанных КАК Т
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Предварительная КАК ВТ
        ПО Т.Реквизит = ВТ.Реквизит И Т.Дата = ВТ.МаксДата
СГРУППИРОВАТЬ ПО
    Т.Реквизит, Т.МаксДата;

Таким образом, соединение по паре Дата + Ссылка гарантирует, что из выборки будет взята ровно одна запись, даже если время документов совпадает до секунды.

Резюме и рекомендации

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

← На главную