При разработке отчетов на Системе компоновки данных (СКД) в 1С программисты часто сталкиваются с классической, но от этого не менее коварной проблемой. Задача звучит просто: нужно отфильтровать строки отчета по значению рассчитанного ресурса (например, вывести только тех контрагентов, сумма продаж по которым превысила 100 000 рублей), но при этом получить абсолютно корректные общие итоги в самом низу таблицы.
Если мы попытаемся решить эту задачу стандартными методами «в лоб», то столкнемся с неприятным поведением платформы. Давайте подробно разберем, почему возникает эта проблема, как работает механизм компоновки данных изнутри и какими способами мы можем элегантно обойти это ограничение платформы.
Для начала давайте проанализируем, как СКД обрабатывает отборы на разных уровнях конфигурации отчета:
ГДЕ в SQL-запросе). Система сначала отсекает все элементарные продажи, которые меньше указанной суммы, а уже потом группирует оставшиеся данные. В результате промежуточные суммы по контрагентам и общие итоги рассчитываются неверно, так как мелкие продажи вообще не попали в расчет.Контрагент), СКД отрабатывает корректно на уровне строк: она рассчитывает сумму продаж по каждому партнеру, а затем скрывает тех, у кого итог не удовлетворяет условию. Однако Общие итоги при этом остаются прежними! Дело в том, что СКД рассчитывает общий итог по всей исходной выборке детальных записей, полностью игнорируя визуальные фильтры, установленные на промежуточных группировках.Ниже мы подробно рассмотрим три практических способа решения этой проблемы, которые помогут вам получить правильные данные в отчете.
Этот метод является наиболее изящным и технологичным, так как он позволяет решить задачу исключительно средствами СКД, не прибегая к изменению исходного запроса. Мы заставим систему пересчитать общие итоги только по тем веткам группировки, которые прошли наш жесткий фильтр.
Разберем этот способ по шагам:
СуммаПродаж) добавим вторую строку в таблицу ресурсов.
Сумма(ВычислитьВыражениеСГруппировкойМассив("Сумма(СуммаПродаж)", "Контрагент", , "Сумма(СуммаПродаж) > 1000"))
Давайте детально разберем, как работает эта конструкция:
ВычислитьВыражениеСГруппировкойМассив обходит все элементы группировки Контрагент.Сумма(СуммаПродаж), которое нужно рассчитать для каждого контрагента."Сумма(СуммаПродаж) > 1000" (вместо фиксированного числа здесь можно использовать параметр СКД, например, &МинимальнаяСумма).Сумма() складывает все элементы полученного массива, формируя честный общий итог, очищенный от отфильтрованных строк.Если по каким-то причинам формулы СКД кажутся вам слишком сложными или отчет работает медленно на больших объемах данных, мы можем перенести логику агрегации на уровень СУБД. Нам нужно сделать так, чтобы итоговая сумма по контрагенту превратилась в обычный реквизит строки, а не рассчитывалась как ресурс компоновки.
Для этого мы перепишем исходный запрос нашего набора данных:
ВЫБРАТЬ
ПродажиОбороты.Контрагент КАК Контрагент,
СУММА(ПродажиОбороты.СуммаОборот) КАК ВсегоПоКонтрагенту
ПОМЕСТИТЬ ВТ_ИтогиПоКонтрагентам
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК ПродажиОбороты
СГРУППИРОВАТЬ ПО
ПродажиОбороты.Контрагент
;
ВсегоПоКонтрагенту из нашей временной таблицы.ВсегоПоКонтрагенту мы указываем роль «Обязательное», чтобы СКД не исключила его при оптимизации запроса. Обратите внимание: это поле не должно быть добавлено в ресурсы отчета на вкладке «Ресурсы»! Для СКД это обычное числовое поле (реквизит).Теперь пользователь может наложить самый обычный отбор на уровне отчета: ВсегоПоКонтрагенту > 1000. Поскольку это поле не является ресурсом, СКД применит фильтр ко всей выборке записей на этапе формирования временных таблиц, и все общие итоги (которые теперь рассчитываются по стандартным ресурсам) сойдутся автоматически.
Этот способ позволяет решить проблему визуального отображения исключительно за счет манипуляций со структурой настроек компоновки данных. Он идеально подходит для отчетов со сложной иерархией, где прописывание формул в ресурсах затруднено.
Выполним следующие настройки в схеме:
Контрагент.СуммаПродаж непосредственно на группировку Контрагент.Давайте проанализируем результат. Визуально пустая корневая группировка будет выглядеть в точности как стандартная строка «Итого». Однако, поскольку наша отфильтрованная группировка по контрагентам теперь находится внутри этой пустой группировки, правила расчета итогов изменятся. Родительская группировка будет суммировать данные только по фактически выведенным дочерним строкам. Мы получим абсолютно верные итоги на экране без изменения запросов и написания сложных функций.
Каждый из рассмотренных способов имеет свои преимущества. Способ с использованием функции ВычислитьВыражениеСГруппировкойМассив универсален и сохраняет стандартный вид настроек. Метод с временными таблицами обеспечивает максимальную производительность на базах данных большого объема. Метод с вложенными группировками незаменим, когда требуется быстрая настройка силами аналитика без изменения схемы компоновки в конфигураторе.