При построении отчетов в Системе компоновки данных (СКД) разработчики часто сталкиваются с необходимостью вывода непрерывной временной шкалы. Для этого в настройках СКД включают механизм дополнения периодов (например, по дням, неделям или месяцам). Однако стандартное поведение СКД может преподнести неприятный сюрприз, если мы попытаемся использовать вычисляемые поля с функцией ВычислитьВыражение для расчета показателей смежных периодов.
В этой статье мы подробно разберем, почему возникает ситуация, когда для пустых (дополненных) периодов вычисляемые поля не отображаются, проанализируем причины такого поведения системы компоновки данных и рассмотрим два практических способа решения этой проблемы.
Рассмотрим классическую задачу. Нам необходимо построить таблицу продаж по контрагентам в разрезе недель. При этом в отчете для каждого периода нужно вывести два показателя: сумму продаж за текущую неделю и сумму продаж за следующую неделю. Для вывода следующей недели мы планируем использовать функцию СКД ВычислитьВыражение.
Предположим, у нас есть контрагент Иванов, по которому были следующие продажи:
Мы хотим получить в отчете следующую картину:
Если в настройках группировки по полю Период мы установим дополнение «Неделя» и пропишем на вкладке «Вычисляемые поля» выражение вида:
ВычислитьВыражение("Сумма(СуммаПродажи)", "Период", , "Следующая", "Следующая")
Мы столкнемся с проблемой: для Недели 2, в которой физически не было продаж, строка вообще не рассчитается и значение следующего периода не выведется. Механизм дополнения периодов визуально достроит Неделю 2 на форме отчета, но вычисляемое поле останется абсолютно пустым.
Выясним причину этого поведения: когда вычисляемое поле задается на вкладке «Вычисляемые поля» в колонке «Выражение», СКД пытается рассчитать его на уровне детальных записей выборки еще до агрегации данных. Но для дополненного периода (Неделя 2) в исходной выборке запроса физически нет ни одной записи. Раз нет записи — нет и контекста для расчета детального вычисляемого поля. Соответственно, функция ВычислитьВыражение даже не вызывается для этой ячейки.
---
Для того чтобы СКД корректно рассчитывала выражение для периодов, которые были добавлены механизмом дополнения, расчет должен происходить на этапе агрегации (после группировки и дополнения данных). Это означает, что поле должно вычисляться как ресурс.
Выполним настройку схемы компоновки данных по шагам:
Шаг 1. Настройка вычисляемого поля
Перейдем на вкладку «Вычисляемые поля» схемы компоновки данных. Добавим новое поле, например, ПродажиСледующегоПериода. При этом колонку «Выражение» обязательно оставляем пустой! Если мы напишем выражение здесь, СКД вернется к попытке расчета на детальных записях, что приведет к исходной ошибке.
Шаг 2. Описание выражения в Ресурсах
Перейдем на вкладку «Ресурсы». Добавим наше поле ПродажиСледующегоПериода в список ресурсов. В колонке «Выражение» пропишем формулу расчета с обработкой возможных значений NULL:
ЕстьNull(ВычислитьВыражение("Сумма(СуммаПродажи)", "Период", , "Следующая", "Следующая"), 0)
В данном случае функция ЕстьNull оборачивает результат работы функции ВычислитьВыражение. Это гарантирует, что если для самого последнего периода отчета следующей недели не существует, в ячейке отобразится красивый ноль, а не пустота.
Шаг 3. Именование группировок в настройках
Чтобы СКД точно понимала, в разрезе какого измерения (оси кросс-таблицы) ей нужно искать «следующую» запись, нам необходимо явно связать второй параметр функции ВычислитьВыражение с нашей группировкой периодов. Для этого:
"Период" (без кавычек в самом свойстве, но соответствующим строковому параметру в формуле ресурса).После выполнения этих шагов СКД сначала сформирует дополненную сетку периодов в памяти, затем сгруппирует данные и только после этого выполнит расчет ресурса ПродажиСледующегоПериода для каждого дополненного интервала времени.
---
Иногда СКД в силу оптимизации запросов или сложных отборов может игнорировать дополнение периодов для конкретных группировок, особенно если у контрагента вообще никогда не было движений по регистру. В таких архитектурно сложных случаях самым надежным методом будет отказ от виртуального дополнения периодов в настройках СКД в пользу формирования жесткой сетки периодов непосредственно в тексте запроса.
Проанализируем этот подход на примере левого соединения с таблицей периодов (например, производственным календарем или виртуальной таблицей дат):
ВЫБРАТЬ РАЗЛИЧНЫЕ
Календарь.Дата КАК Период,
Контрагенты.Ссылка КАК Контрагент
ПОМЕСТИТЬ ВТ_Сетка
ИЗ
Справочник.Контрагенты КАК Контрагенты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПроизводственныйКалендарь КАК Календарь
ПО Календарь.Дата МЕЖДУ &НачалоПериода И &КонецПериода
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Сетка.Период КАК Период,
Сетка.Контрагент КАК Контрагент,
ЕСТЬNULL(ПродажиОбороты.СуммаОборот, 0) КАК СуммаПродажи
ИЗ
ВТ_Сетка КАК Сетка
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ПродажиОбороты
ПО Сетка.Период = ПродажиОбороты.Период
И Сетка.Контрагент = ПродажиОбороты.Контрагент
При таком подходе в итоговой выборке для каждого контрагента физически будет существовать запись на каждый период (каждую неделю), даже если сумма продаж равна нулю.
Важная деталь настройки СКД для второго метода:
Для того чтобы компоновщик данных при оптимизации запроса (например, когда пользователь убирает какие-то поля из отчета) случайно не исключил созданную нами сетку периодов, необходимо зайти на вкладку «Наборы данных», выбрать поле Период и установить для него свойство «Обязательное» (флаг в колонке роли поля).
Поскольку записи теперь существуют в самом наборе данных физически, вычисляемое поле на вкладке «Вычисляемые поля» отработает стандартным образом без переноса логики в ресурсы, так как контекст строки периода гарантированно присутствует.
---
Выбор метода зависит от сложности вашей схемы компоновки данных: