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