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