Как правильно сделать отбор по ресурсу в СКД с сохранением верных итогов?

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При разработке отчетов на Системе компоновки данных (СКД) в 1С программисты часто сталкиваются с классической, но от этого не менее коварной проблемой. Задача звучит просто: нужно отфильтровать строки отчета по значению рассчитанного ресурса (например, вывести только тех контрагентов, сумма продаж по которым превысила 100 000 рублей), но при этом получить абсолютно корректные общие итоги в самом низу таблицы.

Если мы попытаемся решить эту задачу стандартными методами «в лоб», то столкнемся с неприятным поведением платформы. Давайте подробно разберем, почему возникает эта проблема, как работает механизм компоновки данных изнутри и какими способами мы можем элегантно обойти это ограничение платформы.

Выясняем причину: почему СКД ошибается в итогах?

Для начала давайте проанализируем, как СКД обрабатывает отборы на разных уровнях конфигурации отчета:

  1. Отбор на уровне всего отчета (общий отбор). Если мы устанавливаем отбор по ресурсному полю на вкладке «Настройки» всего отчета, СКД пытается наложить это условие на детальные записи (аналог секции ГДЕ в SQL-запросе). Система сначала отсекает все элементарные продажи, которые меньше указанной суммы, а уже потом группирует оставшиеся данные. В результате промежуточные суммы по контрагентам и общие итоги рассчитываются неверно, так как мелкие продажи вообще не попали в расчет.
  2. Отбор на уровне конкретной группировки. Если мы накладываем отбор на саму группировку (например, по полю Контрагент), СКД отрабатывает корректно на уровне строк: она рассчитывает сумму продаж по каждому партнеру, а затем скрывает тех, у кого итог не удовлетворяет условию. Однако Общие итоги при этом остаются прежними! Дело в том, что СКД рассчитывает общий итог по всей исходной выборке детальных записей, полностью игнорируя визуальные фильтры, установленные на промежуточных группировках.

Ниже мы подробно рассмотрим три практических способа решения этой проблемы, которые помогут вам получить правильные данные в отчете.

Способ 1. Принудительный расчет через функцию ВычислитьВыражениеСГруппировкойМассив

Этот метод является наиболее изящным и технологичным, так как он позволяет решить задачу исключительно средствами СКД, не прибегая к изменению исходного запроса. Мы заставим систему пересчитать общие итоги только по тем веткам группировки, которые прошли наш жесткий фильтр.

Разберем этот способ по шагам:

  1. Перейдем на вкладку Ресурсы в схеме компоновки данных.
  2. Для нашего ресурса (например, СуммаПродаж) добавим вторую строку в таблицу ресурсов.
  3. В поле «Рассчитывать по...» для новой строки выберем исключительно значение Общий итог. Это очень важно, так как стандартный расчет для группировок мы трогать не должны.
  4. В колонку «Выражение» для этой строки пропишем следующую формулу:

Сумма(ВычислитьВыражениеСГруппировкойМассив("Сумма(СуммаПродаж)", "Контрагент", , "Сумма(СуммаПродаж) > 1000"))

Давайте детально разберем, как работает эта конструкция:

Способ 2. Реструктуризация запроса с использованием временной таблицы

Если по каким-то причинам формулы СКД кажутся вам слишком сложными или отчет работает медленно на больших объемах данных, мы можем перенести логику агрегации на уровень СУБД. Нам нужно сделать так, чтобы итоговая сумма по контрагенту превратилась в обычный реквизит строки, а не рассчитывалась как ресурс компоновки.

Для этого мы перепишем исходный запрос нашего набора данных:

  1. Создаем ВТ с агрегированными данными. В первом запросе пакета мы группируем продажи по контрагентам и получаем итоговые суммы:

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

Теперь пользователь может наложить самый обычный отбор на уровне отчета: ВсегоПоКонтрагенту > 1000. Поскольку это поле не является ресурсом, СКД применит фильтр ко всей выборке записей на этапе формирования временных таблиц, и все общие итоги (которые теперь рассчитываются по стандартным ресурсам) сойдутся автоматически.

Способ 3. Использование механизма вложенных пустых группировок

Этот способ позволяет решить проблему визуального отображения исключительно за счет манипуляций со структурой настроек компоновки данных. Он идеально подходит для отчетов со сложной иерархией, где прописывание формул в ресурсах затруднено.

Выполним следующие настройки в схеме:

  1. Перейдем на вкладку Настройки, выберем наш вариант отчета и откроем вкладку Другие настройки.
  2. Найдем параметр Расположение общих итогов по вертикали и установим для него значение Нет. Стандартная системная строка итогов внизу отчета исчезнет.
  3. Перейдем к структуре отчета. Нам нужно создать «псевдо-общие итоги». Для этого создадим корневую группировку, но поле группировки указывать не будем (оставим строку пустой). Назовем ее, например, «Итоги по отчету».
  4. Внутрь этой новой пустой группировки перетащим нашу рабочую группировку по полю Контрагент.
  5. Установим отбор по нашему ресурсу СуммаПродаж непосредственно на группировку Контрагент.

Давайте проанализируем результат. Визуально пустая корневая группировка будет выглядеть в точности как стандартная строка «Итого». Однако, поскольку наша отфильтрованная группировка по контрагентам теперь находится внутри этой пустой группировки, правила расчета итогов изменятся. Родительская группировка будет суммировать данные только по фактически выведенным дочерним строкам. Мы получим абсолютно верные итоги на экране без изменения запросов и написания сложных функций.

Каждый из рассмотренных способов имеет свои преимущества. Способ с использованием функции ВычислитьВыражениеСГруппировкойМассив универсален и сохраняет стандартный вид настроек. Метод с временными таблицами обеспечивает максимальную производительность на базах данных большого объема. Метод с вложенными группировками незаменим, когда требуется быстрая настройка силами аналитика без изменения схемы компоновки в конфигураторе.

← На главную