Как вывести только один период в СКД без потери расчета отклонений за предыдущие периоды?

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

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

Если мы попытаемся решить эту задачу «в лоб» — просто установив отбор отчета на текущий месяц, то колонка предыдущего месяца действительно пропадет. Но вместе с ней исчезнут и показатели отклонения, так как СКД не сможет получить данные за прошлый период для расчета разницы. Вычисляемые поля вернут пустые значения или нули.

В этой статье мы подробно разберем, почему так происходит, и рассмотрим четыре практических способа решения этой проблемы: от простой настройки параметров компоновки до оптимизации запроса на уровне СУБД.

Почему стандартный отбор ломает расчеты? Анализируем логику работы СКД

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

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

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

Давайте выясним, как обойти это ограничение платформы.

Способ №1: Штатное решение через настройку свойства «Применение отбора»

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

Разберем по шагам, как это настроить в конфигураторе или в режиме «1С:Предприятие» (в настройках отчета):

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

Что произойдет после изменения этого свойства? СКД изменит порядок выполнения операций. Она получит данные за оба периода, сгруппирует их, успешно выполнит расчет выражения:


ВычислитьВыражение("Сумма(СуммаОстаток)", "КонецПериода", "Группировка", "Текущая", "Текущая") 
- ИстОценка(ВычислитьВыражение("Сумма(СуммаОстаток)", "КонецПериода", "Группировка", "Предыдущая", "Предыдущая"), 0)

И только на самом последнем этапе, перед выводом макета на экран, система применит фильтр группировки и скроет колонку предыдущего месяца. При этом рассчитанное значение отклонения в колонке текущего месяца останется абсолютно корректным.

Способ №2: Оптимальный расчет отклонений на уровне запроса

Несмотря на то, что Способ №1 является полностью рабочим, он имеет существенный недостаток. Если у вас огромная база данных, получение лишних периодов из СУБД, их передача на сервер приложений и последующий расчет в памяти СКД через ВычислитьВыражение могут сильно снизить производительность отчета.

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

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


ВЫБРАТЬ
    ТекущийПериод.Организация КАК Организация,
    ТекущийПериод.Период КАК Период,
    ТекущийПериод.СуммаОстаток КАК ОстатокТекущий,
    ЕСТЬNULL(ПредыдущийПериод.СуммаОстаток, 0) КАК ОстатокПредыдущий,
    ТекущийПериод.СуммаОстаток - ЕСТЬNULL(ПредыдущийПериод.СуммаОстаток, 0) КАК Отклонение
ИЗ
    ВТ_Остатки КАК ТекущийПериод
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ПредыдущийПериод
        ПО ТекущийПериод.Организация = ПредыдущийПериод.Organisaciya
        И ПредыдущийПериод.Период = ДОБАВИТЬКДАТЕ(ТекущийПериод.Период, МЕСЯЦ, -1)

Если СУБД поддерживает оконные (аналитические) функции (например, вы работаете на MS SQL Server или PostgreSQL), этот запрос можно сделать еще изящнее и быстрее без дублирования таблиц с помощью функции LAG:


ВЫБРАТЬ
    Остатки.Организация КАК Организация,
    Остатки.Период КАК Период,
    Остатки.СуммаОстаток КАК ОстатокТекущий,
    LAG(Остатки.СуммаОстаток, 1, 0) OVER (
        PARTITION BY Остатки.Организация 
        ORDER BY Остатки.Период
    ) КАК ОстатокПредыдущий
ИЗ
    ВТ_Остатки КАК Остатки

При таком подходе в схеме компоновки данных нам вообще не понадобятся сложные вычисляемые поля. Мы сможем наложить обычный глобальный отбор на отчет по текущему периоду. СУБД сама рассчитает разницу на основе исторических данных, а СКД выведет уже готовое поле Отклонение на экран.

Способ №3: Использование Условного оформления для визуального скрытия колонок

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

Реализуется это через механизм Условного оформления СКД. Давайте проанализируем этот процесс:

  1. Перейдем на вкладку «Настройки» в схеме компоновки, выберем весь отчет или конкретную таблицу.
  2. Откроем вкладку «Условное оформление» и добавим новый элемент.
  3. В поле «Оформление» найдем свойства МинимальнаяШирина и МаксимальнаяШирина. Установим их в значение 0 (или в крайнем случае 0.1, если платформа не позволяет сжать колонку до абсолютного нуля).
  4. В поле «Условие» укажем параметр фильтрации: наше поле периода (например, КонецПериода) должно быть Не равно нашему целевому (текущему) месяцу.
  5. В поле «Оформляемые поля» выберем те поля и ресурсы группировки периода, которые выводятся для старого месяца и которые мы хотим спрятать.

При формировании отчета система рассчитает все данные за оба месяца (что гарантирует корректную работу функции ВычислитьВыражение), но при генерации табличного документа колонки прошлого периода просто «сожмутся» и станут невидимыми для пользователя.

Способ №4: Ограничение вывода данных через ресурсы

Еще один интересный обходной путь — рассчитывать значения ресурсов выборочно. Мы можем оставить группировку по периодам нетронутой, но переопределить вывод числовых показателей.

Создадим новое вычисляемое поле в СКД, назовем его, например, ОстатокПоказываемый. В выражении этого поля пропишем логику:


ВЫБОР 
    КОГДА КонецПериода = &ТекущийМесяц 
        ТОГДА СуммаОстаток 
    ИНАЧЕ 0 
КОНЕЦ

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

Сравнительный анализ решений: какой метод выбрать?

Давайте сопоставим все рассмотренные методы, чтобы вы могли выбрать наиболее подходящий под ваши задачи:

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

Применяя эти методики, вы сможете создавать гибкие, быстрые и визуально понятные для пользователей отчёты в системе 1С:Предприятие.

← На главную