При разработке отчетов в Системе компоновки данных (СКД) программисты часто сталкиваются с задачей вывода оборотов или остатков в разрезе периодов (например, по месяцам, неделям или дням). Типичный сценарий: создается вспомогательный набор данных с календарем (периодами) и основной набор данных (запрос к виртуальной таблице оборотов регистра), после чего они связываются по параметрам начала и конца периода. Однако при формировании отчета за год можно обнаружить неприятное поведение: в строке каждого месяца выводится одна и та же сумма, равная общему обороту за весь год.
В этой статье мы подробно проанализируем, почему возникает эта проблема, разберем особенности работы механизмов СКД и рассмотрим несколько практических способов ее решения, включая динамическую смену периодичности.
---
Выясним причину такого поведения компоновщика. Когда мы создаем подчиненный набор данных (запрос к виртуальной таблице оборотов регистра) и оставляем включенным флаг «Автозаполнение», СКД берет управление параметрами в свои руки. Платформа видит в подчиненном запросе параметры &НачПериода и &КонПериода и автоматически связывает их с глобальными одноименными параметрами всей схемы компоновки данных.
В результате, когда СКД выполняет компоновку и формирует запросы к СУБД, она полностью игнорирует значения дат, которые должны передаваться из родительского набора данных (помесячного календаря) через настройки связи. Вместо передачи помесячных границ в параметры &НачПериода и &КонПериода подставляются глобальные даты начала и конца общего интервала отчета (например, границы года). Таким образом, подчиненный запрос выполняется один раз за весь год, а полученная общая сумма дублируется во всех строках-месяцах родительской таблицы.
---
Если архитектура вашего отчета строго требует использования двух наборов данных (например, когда таблица периодов строится по сложному алгоритму), необходимо правильно настроить связь между ними в обход механизма автозаполнения. Разберем этот процесс по шагам:
Выбрать
ХозрасчетныйОбороты.Субконто1 КАК Статья,
ХозрасчетныйОбороты.СуммаОборот КАК СуммаОстаток
{ВЫБРАТЬ
Статья,
СуммаОстаток}
Из
РегистрБухгалтерии.Хозрасчетный.Обороты(&СвязьНачПериода, &СвязьКонПериода, , , , , , ) КАК ХозрасчетныйОбороты
&СвязьНачПериода и &СвязьКонПериода. Это критически важно, чтобы избежать пересечения с глобальными параметрами схемы.НачалоПериода).СвязьНачПериода.СвязьКонПериода.Важное предупреждение о производительности: Связывание наборов данных через передачу параметров в виртуальные таблицы СУБД на уровне платформы преобразуется в выполнение отдельных запросов в цикле. Если в отчете будет выбрана периодичность «День» за год, система выполнит 365 отдельных тяжелых запросов к базе данных, что приведет к катастрофическому падению скорости формирования отчета. Рассмотрим более оптимальные альтернативы.
---
Если перед нами стоит задача предоставить пользователю возможность динамически менять периодичность отчета (День, Месяц, Квартал, Год) и при этом мы хотим обойтись одним эффективным запросом, мы можем использовать конструкцию ВЫБОР КОГДА в тексте запроса СКД.
Проанализируем пример реализации такого подхода. Мы вводим пользовательский строковый параметр &Период, который может принимать значения "День", "Месяц", "Год". Текст запроса будет выглядеть следующим образом:
ВЫБРАТЬ
ВЫБОР &Период
КОГДА "День" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, ДЕНЬ)
КОГДА "Месяц" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, МЕСЯЦ)
КОГДА "Год" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, ГОД)
КОНЕЦ КАК ПериодНачало,
ВЫБОР &Период
КОГДА "День" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, ДЕНЬ)
КОГДА "Месяц" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, МЕСЯЦ)
КОГДА "Год" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, ГОД)
КОНЕЦ КАК ПериодКонец,
ХозрасчетныйОбороты.Субконто1 КАК Статья,
СУММА(ХозрасчетныйОбороты.СуммаОборот) КАК СуммаОборот
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(&НачПериода, &КонПериода, Регистратор, , , , , ) КАК ХозрасчетныйОбороты
СГРУППИРОВАТЬ ПО
ХозрасчетныйОбороты.Субконто1,
ВЫБОР &Период
КОГДА "День" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, ДЕНЬ)
КОГДА "Месяц" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, МЕСЯЦ)
КОГДА "Год" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, ГОД)
КОНЕЦ,
ВЫБОР &Период
КОГДА "День" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, ДЕНЬ)
КОГДА "Месяц" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, МЕСЯЦ)
КОГДА "Год" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, ГОД)
КОНЕЦ
В данном случае в параметрах виртуальной таблицы оборотов в качестве периодичности мы указываем Регистратор (или Запись). Это позволяет СУБД возвращать детальные записи по каждой транзакции с точной датой в поле Период, которую мы затем динамически округляем до нужной пользователю периодичности.
---
Наиболее лаконичным и платформенным решением для получения корректных итогов по периодам является использование значения Авто в параметре периодичности виртуальной таблицы. Посмотрим, как это упрощает логику запроса:
ВЫБРАТЬ
ХозрасчетныйОбороты.Субконто1 КАК Статья,
ХозрасчетныйОбороты.Организация КАК Организация,
ХозрасчетныйОбороты.СуммаОборот КАК СуммаОстаток,
ХозрасчетныйОбороты.ПериодМесяц КАК ПериодМесяц,
ХозрасчетныйОбороты.ПериодДень КАК ПериодДень
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(&НачПериода, &КонПериода, Авто, , , , , ) КАК ХозрасчетныйОбороты
При использовании ключевого слова Авто виртуальная таблица автоматически добавляет в схему компоновки данных все возможные поля периодов: ПериодСекунда, ПериодМинута, ПериодЧас, ПериодДень, ПериодНеделя, ПериодДекада, ПериодМесяц, ПериодКвартал, ПериодПолугодие, ПериодГод, а также поля Регистратор и НомерСтроки.
После этого вам достаточно в настройках структуры отчета (на вкладке «Настройки» в СКД) добавить группировку по нужному вам полю (например, по ПериодМесяц). Система самостоятельно оптимизирует SQL-запрос под выбранную группировку, и вы получите корректные помесячные обороты без дублирования годовых сумм.
---
Зачастую разработчики используют дополнительный набор данных с календарем только для одной цели — чтобы в итоговом отчете выводились строки даже за те месяцы, в которых у организации не было никаких оборотов. Но в системе компоновки данных есть мощный встроенный механизм, решающий эту задачу за один шаг без написания лишнего кода.
Рассмотрим, как его настроить:
Авто.ПериодМесяц.ПериодМесяц, перейдите в свойства этой группировки (в правом нижнем углу конструктора настроек СКД) и найдите раздел «Дополнение».Месяц.&НачПериода и &КонПериода).Теперь платформа самостоятельно сгенерирует дополняющие строки с нулевыми показателями для тех месяцев, по которым в базе данных не было зарегистрировано движений. Это избавит вас от необходимости проектирования сложных запросов-календарей.
---
Подведем итог. Если вы столкнулись с тем, что СКД выводит годовой итог вместо помесячного, это верный признак того, что у вас включено автозаполнение, а связь между наборами данных по стандартным параметрам нарушена.
Для простых отчетов с фиксированным периодом мы рекомендуем использовать Решение №3 (периодичность Авто). Для отчетов, где требуется гарантированный вывод пустых месяцев, идеальным выбором будет Решение №4 (дополнение периодов силами СКД). К созданию двух наборов данных и ручной настройке параметров связи (Решение №1) следует прибегать только в исключительных случаях, помня о возможных проблемах с производительностью на больших объемах данных.