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