При разработке отчетов и аналитических выборок в 1С часто возникает задача многоуровневой агрегации данных. Классический пример: в табличной части документа отражены технологические операции, где поле суммы необходимо просуммировать полностью (так как каждая операция увеличивает себестоимость), а количество необходимо взять только один раз за весь документ (максимальное или итоговое по операции) и сложить эти максимумы между всеми документами за период.
Попытка решить такую задачу в одном запросе с простой группировкой приводит к ошибке: агрегатная функция СУММА либо суммирует все строки документа, задваивая количество, либо при расчете МАКСИМУМ платформа берет максимальное значение по всей выборке, а не сумму максимумов. Рассмотрим подробнее, как правильно реализовать подобный расчет и решить сопутствующую проблему объединения разнородных выборок.
Проанализируем механику работы языка запросов 1С. В секции ИТОГИ или при группировке функция СУММА всегда рассчитывается по детальным записям источника данных. Чтобы получить сумму максимумов, необходимо разделить расчет на два последовательных шага с использованием временной таблицы.
Разберем по шагам создание пакетного запроса:
СУММА, а для поля количества — МАКСИМУМ. Таким образом, по каждому отдельному документу мы получаем его суммарную стоимость и его максимальный объем обработки.СУММА.Посмотрим на пример практической реализации данного запроса:
ВЫБРАТЬ
ДокументОперации.Номенклатура КАК Номенклатура,
ДокументОперации.Ссылка КАК ДокументСсылка,
МАКСИМУМ(ДокументОперации.КоличествоОбработано) КАК МаксКоличество,
СУММА(ДокументОперации.Сумма) КАК Сумма
ПОМЕСТИТЬ ВТ_СвернутыеПоДокументам
ИЗ
Документ.ТехнологическаяОперация.Операции КАК ДокументОперации
ГДЕ
ДокументОперации.Ссылка.Проведен = ИСТИНА
И ДокументОперации.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
СГРУППИРОВАТЬ ПО
ДокументОперации.Номенклатура,
ДокументОперации.Ссылка
ИНДЕКСИРОВАТЬ ПО
Номенклатура,
ДокументСсылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ.Номенклатура КАК Номенклатура,
СУММА(ВТ.МаксКоличество) КАК ИтоговоеКоличество,
СУММА(ВТ.Сумма) КАК ИтоговаяСумма
ИЗ
ВТ_СвернутыеПоДокументам КАК ВТ
СГРУППИРОВАТЬ ПО
ВТ.Номенклатура
Важный момент: если временная таблица в дальнейшем участвует в соединениях с другими источниками, обязательно добавляйте предложение ИНДЕКСИРОВАТЬ ПО для полей связи. Это позволит оптимизатору СУБД построить эффективный план выполнения запроса.
Если отчет разрабатывается с использованием Системы компоновки данных (СКД), усложнять текст запроса временными таблицами не обязательно. СКД предоставляет специальные функции для работы с агрегатами массивов.
Разберем настройку расчета ресурсов в СКД:
КоличествоОбработано в колонке «Выражение» задаем расчет через агрегацию массива:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(КоличествоОбработано)", "ДокументСсылка"))
Данная конструкция сначала рассчитывает максимальное значение поля для каждой группировки по документу, помещает результат в массив значений, а на уровне вышестоящих группировок (номенклатура, иерархия, общий итог) суммирует полученные элементы массива.
Когда требуется соединить в одном отчете разные операции (например, списания/выпуск из технологических операций и приход из документов поступления продукции), часто применяется оператор ОБЪЕДИНИТЬ ВСЕ. При этом возникает ситуация, когда в одной ветке запроса полей больше, чем в другой.
Выясним правила корректного выравнивания колонок:
NULL рекомендуется использовать явное приведение типов с помощью ВЫРАЗИТЬ или литералы нужного типа. Для чисел лучше задавать 0, а для строк — пустую строку "". Это предотвращает ошибки несовместимости типов в СУБД и избавляет от необходимости применять функцию ЕСТЬNULL на последующих этапах.Посмотрим на пример объединения двух разнородных источников:
ВЫБРАТЬ
Операции.Номенклатура КАК Номенклатура,
Операции.ТехОперация КАК ТехОперация,
Операции.КоличествоОбработано КАК Количество,
Операции.Сумма КАК Сумма
ИЗ
ВТ_Операции КАК Операции
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Поступления.Номенклатура,
ЗНАЧЕНИЕ(Справочник.ТехнологическиеОперации.ПустаяСсылка),
Поступления.Количество,
ВЫРАЗИТЬ(0 КАК ЧИСЛО(15, 2))
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК Поступления
Рекомендация по оптимизации: если конфигурация использует регистры накопления для учета затрат и выпуска продукции, предпочтительно строить выборки к виртуальным таблицам Обороты или ОстаткиИОбороты, а не к табличным частям документов. Это значительно ускоряет работу запроса и автоматически фильтрует непроведенные документы.