При создании аналитических отчетов в Системе компоновки данных (СКД) разработчики часто сталкиваются с задачей отображения динамики показателей. Типичный пример — отчет по остаткам или оборотам, в котором требуется показать данные за текущий месяц и отклонение (разницу) по сравнению с предыдущим месяцем. При этом на экране пользователь хочет видеть только одну колонку — текущий период.
Если мы попытаемся решить эту задачу «в лоб» — просто установив отбор отчета на текущий месяц, то колонка предыдущего месяца действительно пропадет. Но вместе с ней исчезнут и показатели отклонения, так как СКД не сможет получить данные за прошлый период для расчета разницы. Вычисляемые поля вернут пустые значения или нули.
В этой статье мы подробно разберем, почему так происходит, и рассмотрим четыре практических способа решения этой проблемы: от простой настройки параметров компоновки до оптимизации запроса на уровне СУБД.
Для того чтобы понять суть проблемы, нам необходимо заглянуть под капот Системы компоновки данных и проанализировать последовательность выполнения операций при формировании отчета. Упрощенная схема жизненного цикла данных в СКД выглядит следующим образом:
ВычислитьВыражение.Если мы накладываем стандартный отбор на отчет или на детальные записи, СКД отфильтровывает прошлый период еще на шаге 2. В итоге на шаге 4 функция ВычислитьВыражение, которая пытается обратиться к предыдущему периоду, просто не находит нужных строк в таблице данных. Результат вычисления становится равен нулю.
Давайте выясним, как обойти это ограничение платформы.
Самый быстрый способ решить проблему без изменения запроса и архитектуры отчета — изменить момент времени, когда СКД накладывает фильтр на группировку. Мы заставим систему сначала рассчитать все ресурсы и вычисляемые поля для обоих месяцев, а уже потом — скрыть ненужный нам прошлый период.
Разберем по шагам, как это настроить в конфигураторе или в режиме «1С:Предприятие» (в настройках отчета):
Период или КонецПериода). Важно: отбор нужно накладывать не на весь отчет, а именно на эту конкретную группировку колонок!КонецПериода) должно быть равно требуемому значению (например, началу или концу текущего месяца).Авто.Что произойдет после изменения этого свойства? СКД изменит порядок выполнения операций. Она получит данные за оба периода, сгруппирует их, успешно выполнит расчет выражения:
ВычислитьВыражение("Сумма(СуммаОстаток)", "КонецПериода", "Группировка", "Текущая", "Текущая")
- ИстОценка(ВычислитьВыражение("Сумма(СуммаОстаток)", "КонецПериода", "Группировка", "Предыдущая", "Предыдущая"), 0)
И только на самом последнем этапе, перед выводом макета на экран, система применит фильтр группировки и скроет колонку предыдущего месяца. При этом рассчитанное значение отклонения в колонке текущего месяца останется абсолютно корректным.
Несмотря на то, что Способ №1 является полностью рабочим, он имеет существенный недостаток. Если у вас огромная база данных, получение лишних периодов из СУБД, их передача на сервер приложений и последующий расчет в памяти СКД через ВычислитьВыражение могут сильно снизить производительность отчета.
Гораздо более профессиональным и производительным подходом является расчет всех отклонений непосредственно в SQL-запросе. В СКД мы должны передавать уже готовые цифры. Рассмотрим, как это сделать с помощью левого соединения таблицы самой с собой.
Допустим, наш исходный запрос получает остатки по месяцам. Мы можем преобразовать его следующим образом:
ВЫБРАТЬ
ТекущийПериод.Организация КАК Организация,
ТекущийПериод.Период КАК Период,
ТекущийПериод.СуммаОстаток КАК ОстатокТекущий,
ЕСТЬNULL(ПредыдущийПериод.СуммаОстаток, 0) КАК ОстатокПредыдущий,
ТекущийПериод.СуммаОстаток - ЕСТЬNULL(ПредыдущийПериод.СуммаОстаток, 0) КАК Отклонение
ИЗ
ВТ_Остатки КАК ТекущийПериод
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ПредыдущийПериод
ПО ТекущийПериод.Организация = ПредыдущийПериод.Organisaciya
И ПредыдущийПериод.Период = ДОБАВИТЬКДАТЕ(ТекущийПериод.Период, МЕСЯЦ, -1)
Если СУБД поддерживает оконные (аналитические) функции (например, вы работаете на MS SQL Server или PostgreSQL), этот запрос можно сделать еще изящнее и быстрее без дублирования таблиц с помощью функции LAG:
ВЫБРАТЬ
Остатки.Организация КАК Организация,
Остатки.Период КАК Период,
Остатки.СуммаОстаток КАК ОстатокТекущий,
LAG(Остатки.СуммаОстаток, 1, 0) OVER (
PARTITION BY Остатки.Организация
ORDER BY Остатки.Период
) КАК ОстатокПредыдущий
ИЗ
ВТ_Остатки КАК Остатки
При таком подходе в схеме компоновки данных нам вообще не понадобятся сложные вычисляемые поля. Мы сможем наложить обычный глобальный отбор на отчет по текущему периоду. СУБД сама рассчитает разницу на основе исторических данных, а СКД выведет уже готовое поле Отклонение на экран.
Если вы не хотите менять структуру запроса или возиться с тонкими настройками применения отборов, можно пойти по пути визуальной маскировки. Мы оставим в выборке оба месяца, но сделаем так, чтобы пользователь физически не видел колонку предыдущего месяца на экране.
Реализуется это через механизм Условного оформления СКД. Давайте проанализируем этот процесс:
МинимальнаяШирина и МаксимальнаяШирина. Установим их в значение 0 (или в крайнем случае 0.1, если платформа не позволяет сжать колонку до абсолютного нуля).КонецПериода) должно быть Не равно нашему целевому (текущему) месяцу.При формировании отчета система рассчитает все данные за оба месяца (что гарантирует корректную работу функции ВычислитьВыражение), но при генерации табличного документа колонки прошлого периода просто «сожмутся» и станут невидимыми для пользователя.
Еще один интересный обходной путь — рассчитывать значения ресурсов выборочно. Мы можем оставить группировку по периодам нетронутой, но переопределить вывод числовых показателей.
Создадим новое вычисляемое поле в СКД, назовем его, например, ОстатокПоказываемый. В выражении этого поля пропишем логику:
ВЫБОР
КОГДА КонецПериода = &ТекущийМесяц
ТОГДА СуммаОстаток
ИНАЧЕ 0
КОНЕЦ
Затем в ресурсах отчета мы укажем, что суммировать нужно именно это новое поле ОстатокПоказываемый. Поле отклонения по-прежнему будет использовать для расчетов исходное поле СуммаОстаток (которое содержит данные за оба месяца). В результате в колонке предыдущего месяца везде отобразятся нули, которые легко убрать через формат поля (скрыть нулевые значения), а колонка текущего периода покажет реальные остатки и правильную разницу.
Давайте сопоставим все рассмотренные методы, чтобы вы могли выбрать наиболее подходящий под ваши задачи:
Применяя эти методики, вы сможете создавать гибкие, быстрые и визуально понятные для пользователей отчёты в системе 1С:Предприятие.