При разработке отчетов на схеме компоновки данных (СКД) с использованием виртуальных таблиц ОстаткиИОбороты программисты часто сталкиваются со следующей проблемой. Допустим, у нас есть данные по остаткам за несколько месяцев. В январе пришло 100 рублей, в феврале и марте движений не было, а в апреле снова произошел приход. Нам необходимо, чтобы в отчете за каждый месяц (январь, февраль, март, апрель) выводился актуальный конечный остаток. Однако по умолчанию СКД выводит строки только за январь и апрель, а февраль и март просто пропускает или показывает там нулевой остаток.
Для решения этой проблемы в СКД предусмотрен механизм дополнения периодов. Но при его включении разработчики моментально наталкиваются на жесткие ограничения платформы: невозможность использовать произвольную сортировку, ошибки при попытке сгруппировать данные по красивому представлению периода (например, "Январь 2018") и конфликты полей группировки. В этой статье мы подробно разберем, как заставить дополнение периодов работать корректно, сохраняя при этом нужный вид отчета и правильную сортировку.
Виртуальная таблица ОстаткиИОбороты возвращает данные только за те периоды, в которых были совершены реальные движения (зарегистрированы регистраторы). Если движений в каком-то месяце не было, база данных физически не содержит этой строки. СКД пытается рассчитать остаток, но без строки периода ей просто негде его отобразить.
Для того чтобы принудительно сгенерировать недостающие строки дат, используется механизм дополнения периодов в настройках группировки СКД. Однако чтобы этот механизм отработал корректно, СКД должна четко понимать структуру данных. Рассмотрим, какие настройки необходимо сделать на уровне набора данных в первую очередь.
Прежде чем включать дополнение в настройках отчета, обязательно проверьте вкладку «Наборы данных» в конструкторе СКД. Без правильной разметки ролей дополнение работать не будет:
Период). В колонке «Роль» должно быть указано, что это поле-период. Ему необходимо присвоить соответствующий тип периода (день, месяц, квартал) и порядковый номер (уровень иерархии). Если у вас в запросе несколько периодов, у самого младшего (секунда, регистратор) уровень должен быть равен 1, у дня — 2, у месяца — 3 и так далее.Измерение. Если СКД не определит измерения, она не сможет сообразить, в разрезе какого склада или товара нужно переносить остаток на «пустой» месяц, и строки дополнения не появятся.Перейдем к настройке структуры отчета на вкладке «Настройки»:
ПериодМесяц).ДвиженияИГраницыПериода. Это заставит систему дополнять периоды внутри интервала от первого до последнего движения.&НачалоПериода и &КонецПериода).После этого система начнет выводить пустые месяцы. Но тут мы сталкиваемся со следующей проблемой: поле дополнения имеет тип Дата (например, 01.02.2018 00:00:00). Выводить пользователю сухие даты начала месяца некрасиво. Нам нужно представление вида "Февраль 2018", а также сортировка по году и месяцу.
Если мы добавим в группировку строковое поле периода или поля года/месяца для сортировки, СКД выдаст ошибку:
Дополнение может быть выполнено только по одному полю или Нельзя в одной группировке использовать поле периода с другим полем.
Проанализируем три способа решения этой проблемы.
Это самый правильный и изящный способ, который не требует изменения структуры запроса или создания лишних полей группировки. Мы оставляем группировку строго по одному полю даты, но настраиваем его свойства так, чтобы оно отображалось и сортировалось так, как нам нужно.
Перейдите на вкладку «Наборы данных», найдите ваше поле периода (например, ПериодМесяц) и настройте следующие параметры:
ДФ='MMMM yyyy'. На выходе пользователь увидит понятное «Январь 2018», «Февраль 2018», при этом для системы поле останется полноценной датой.Формат(ПериодМесяц, "ДФ='MMMM yyyy'").Таким образом, в настройках структуры отчета у вас остается группировка только по одному полю ПериодМесяц. Дополнение работает идеально, а пользователь видит красивые названия месяцев в правильном хронологическом порядке.
Если вам обязательно нужно использовать в отчете кастомные текстовые поля, полученные путем вычислений (например, выборка кварталов или текстовых представлений с условиями), перенесите эту логику из основного запроса в «Вычисляемые поля» СКД.
Рассмотрим, почему это помогает обойти ошибку дополнения:
ВЫБОР КОГДА), СКД видит эти поля как независимые физические поля набора данных и конфликтует при попытке применить дополнение к одному из них в рамках одной группировки.Посмотрим на пример настройки вычисляемого поля:
ПредставлениеПериода.Формат(ПериодМесяц, "ДФ='MMMM yyyy'") или используйте более сложные функции работы с датами СКД.ПериодМесяц, а в выбранных полях или в качестве представления выводите ваше вычисляемое поле.Бывают сложные случаи, когда стандартный механизм дополнения СКД по каким-то причинам не подходит или работает некорректно (например, при сложных объединениях или внешних наборах данных). В этом случае мы можем применить классический архитектурный паттерн — генерацию периодов через связь наборов данных.
Идея заключается в том, чтобы разделить получение периодов и получение самих данных на два разных запроса в СКД:
НаборДанных1 (Запрос-Календарь): Этот запрос должен возвращать нам исключительно список всех возможных периодов (месяцев) в выбранном интервале. Пример такого запроса на основе производственной закупки или регламентированного календаря (также можно сгенерировать периоды автоподбором из системных таблиц):
ВЫБРАТЬ РАЗЛИЧНЫЕ
НАЧАЛОПЕРИОДА(РегламентированныйПроизводственныйКалендарь.Дата, МЕСЯЦ) КАК ПериодМесяц,
ПредставлениеПериода КАК ИмяМесяца
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
ГДЕ
РегламентированныйПроизводственныйКалендарь.Дата МЕЖДУ &НачалоПериода И &КонецПериода
НаборДанных2 (Запрос-Данные): Это ваш основной запрос к виртуальной таблице остатков и оборотов регистра накопления. Он выбирает только реальные движения.
Теперь свяжем эти наборы на вкладке «Связи наборов данных»:
ПериодМесяц = ПериодМесяц.При таком подходе НаборДанных1 гарантированно вернет строки для каждого месяца из выбранного интервала времени. Даже если во втором наборе (в реальных данных) за какой-то месяц не будет ни одной записи, строка периода все равно отобразится в отчете за счет левого соединения, выполненного процессором компоновки данных. При этом вы полностью свободны в сортировке и группировке полей первого набора, ведь системный механизм дополнения периодов группировки вам больше не требуется.
Если вы выводите в дополненные периоды детальные записи (например, поле Регистратор), помните, что в тех месяцах, которые были добавлены искусственно механизмом дополнения, поле регистратора вернет значение NULL.
Это может привести к тому, что остатки поползут или строки начнут некрасиво двоиться. Чтобы этого избежать, обязательно найдите поле Регистратор на вкладке «Наборы данных» и в настройках его роли установите флаг «Игнорировать NULL». Это укажет процессору компоновки данных, что строки с пустыми регистраторами в дополненных периодах не нужно выделять в отдельные пустые записи, а следует корректно агрегировать их и переносить на них накопленный остаток предыдущих периодов.
Используя предложенные методы, вы сможете создавать профессиональные и визуально привлекательные отчёты со стабильным расчетом остатков по временной шкале без раздражающих пользователя пропусков данных.