При разработке отчетов в 1С программисты часто сталкиваются с задачей, когда стандартные итоги не позволяют получить нужный результат. Типичный пример: необходимо найти максимальный остаток товара в разрезе каждой организации, а в общем итоге получить не общий максимум, а сумму этих максимумов. Стандартная конструкция ИТОГИ в языке запросов работает линейно и не позволяет выполнять вложенную агрегацию (агрегат от агрегата) в одну итерацию.
В этой статье мы подробно разберем, почему обычный запрос выдает неверный результат, и рассмотрим два надежных способа решения задачи: через временные таблицы и с помощью мощных механизмов Системы компоновки данных (СКД).
Рассмотрим ситуацию, описанную автором темы. В запросе используется предложение ИТОГИ МАКСИМУМ(ОстатокКоличество) ПО Организация. Если мы попытаемся добавить расчет общего итога по всем организациям, система столкнется с ограничением: для поля «Общий итог» она применит ту же функцию МАКСИМУМ ко всей выборке. В результате мы увидим самое большое значение среди всех организаций, а не их сумму.
Проанализируем пример кода автора:
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Организация КАК Организация,
ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
ТоварыНаСкладахОстатки.ВНаличииОстаток КАК ОстатокКоличество
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата) КАК ТоварыНаСкладахОстатки
ИТОГИ
МАКСИМУМ(ОстатокКоличество)
ПО
Организация
Если в организации №1 максимум по товару равен 10, а в организации №2 — 20, то общий итог при использовании МАКСИМУМ покажет 20. Наша же цель — получить 30 (10 + 20). Чтобы добиться этого, нужно изменить подход к построению запроса или настройки отчета.
Если вы не используете СКД и вам нужно получить результат программно (в коде обработки), единственный верный путь — это разделение задачи на два этапа с использованием временных таблиц. Выясним алгоритм действий:
Разберем пример реализации этого метода:
// Шаг 1: Получаем максимумы во временную таблицу
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Организация КАК Организация,
МАКСИМУМ(ТоварыНаСкладахОстатки.ВНаличииОстаток) КАК МаксОстаток
ПОМЕСТИТЬ ВтМаксимальныеОстатки
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата) КАК ТоварыНаСкладахОстатки
СГРУППИРОВАТЬ ПО
Организация;
// Шаг 2: Складываем эти максимумы
ВЫБРАТЬ
МаксимальныеОстатки.Организация,
МаксимальныеОстатки.МаксОстаток
ИЗ
ВтМаксимальныеОстатки КАК МаксимальныеОстатки
ИТОГИ
СУММА(МаксОстаток)
ПО
ОБЩИЕ
В этом случае в поле ОБЩИЕ мы получим корректную сумму значений МаксОстаток. Однако этот метод неудобен, если в отчете нужны детальные записи по номенклатуре, так как соединение детальных записей с агрегатами во временных таблицах может сильно усложнить запрос.
Поскольку большинство современных отчетов строится на СКД, наиболее правильным и гибким решением будет использование функций компоновки данных. Рассмотрим, как настроить расчет ресурсов для получения суммы максимумов.
Важное правило: При работе с СКД крайне не рекомендуется использовать ключевое слово ИТОГИ непосредственно в тексте запроса. Это мешает системе компоновки самостоятельно управлять итогами и может приводить к дублированию данных или ошибкам производительности.
Для решения нашей задачи в СКД на вкладке «Ресурсы» необходимо настроить разные формулы расчета для разных уровней группировок. Разберем пошагово:
ОстатокКоличество в список ресурсов.Максимум(ОстатокКоличество).Организация и Номенклатура).Для расчета общего итога в СКД существует специальная функция ВычислитьВыражениеСГруппировкойМассив. Проанализируем ее синтаксис:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(ОстатокКоличество)", "Организация"))
Как это работает:
ВычислитьВыражениеСГруппировкойМассив обходит все группировки Организация.Максимум(ОстатокКоличество).Сумма складывает все элементы этого массива, давая нам искомую сумму максимумов в строке общих итогов.В сообщении №9 автор приводит пример запроса с левым соединением регистра остатков и регистра резервов. Посмотрим на ситуацию внимательнее. При соединении таблиц в запросе часто возникает проблема «размножения» строк. Если у одной позиции номенклатуры в одной организации есть несколько записей в таблице резервов, то основная строка остатков будет продублирована столько же раз.
Если в таком «раздутом» запросе использовать СУММА, результат будет завышен. Использование МАКСИМУМ на уровне группировки Организация помогает отсечь дубли, но именно поэтому последующий расчет общего итога через ВычислитьВыражениеСГруппировкойМассив становится критически важным — он позволяет «схлопнуть» данные корректно на каждом уровне.
Совет: При работе с виртуальными таблицами остатков старайтесь передавать все необходимые измерения (Организация, Номенклатура) в параметры виртуальной таблицы, а не фильтровать их в секции ГДЕ. Это значительно повышает скорость выполнения запроса.
Мы проанализировали проблему расчета сложных итогов и выяснили:
ИТОГИ не умеет суммировать результаты других агрегатных функций для общего итога.Максимум для группировок и ВычислитьВыражениеСГруппировкойМассив для расчета общего итога как суммы этих максимумов.Применение этих методов позволит вам создавать точные управленческие отчеты любой сложности, избегая типичных ошибок в расчете остатков и резервов.