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