Как в СКД вывести обороты за каждый месяц, если вместо этого выводится общий итог за год в каждой строке?

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

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

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

---

Почему отчет выводит итог за весь год вместо помесячных данных?

Выясним причину такого поведения компоновщика. Когда мы создаем подчиненный набор данных (запрос к виртуальной таблице оборотов регистра) и оставляем включенным флаг «Автозаполнение», СКД берет управление параметрами в свои руки. Платформа видит в подчиненном запросе параметры &НачПериода и &КонПериода и автоматически связывает их с глобальными одноименными параметрами всей схемы компоновки данных.

В результате, когда СКД выполняет компоновку и формирует запросы к СУБД, она полностью игнорирует значения дат, которые должны передаваться из родительского набора данных (помесячного календаря) через настройки связи. Вместо передачи помесячных границ в параметры &НачПериода и &КонПериода подставляются глобальные даты начала и конца общего интервала отчета (например, границы года). Таким образом, подчиненный запрос выполняется один раз за весь год, а полученная общая сумма дублируется во всех строках-месяцах родительской таблицы.

---

Решение №1. Корректная настройка связи двух наборов данных

Если архитектура вашего отчета строго требует использования двух наборов данных (например, когда таблица периодов строится по сложному алгоритму), необходимо правильно настроить связь между ними в обход механизма автозаполнения. Разберем этот процесс по шагам:

  1. Отключите автозаполнение в подчиненном наборе данных (запросе к оборотам). На вкладке «Наборы данных» снимите флаг «Автозаполнение» для этого запроса.
  2. Поскольку автозаполнение отключено, вам потребуется вручную описать доступные для СКД поля и параметры в тексте запроса, используя фигурные скобки. Например:
    
    Выбрать
        ХозрасчетныйОбороты.Субконто1 КАК Статья,
        ХозрасчетныйОбороты.СуммаОборот КАК СуммаОстаток
    {ВЫБРАТЬ
        Статья,
        СуммаОстаток}
    Из
        РегистрБухгалтерии.Хозрасчетный.Обороты(&СвязьНачПериода, &СвязьКонПериода, , , , , , ) КАК ХозрасчетныйОбороты
    
  3. Обратите внимание, что в параметрах виртуальной таблицы мы использовали новые имена: &СвязьНачПериода и &СвязьКонПериода. Это критически важно, чтобы избежать пересечения с глобальными параметрами схемы.
  4. Перейдите на вкладку «Параметры» и для созданных параметров связи установите флаг «Ограничение доступности». Пользователю не нужно видеть эти технические параметры в настройках отчета.
  5. Перейдите на вкладку «Связи наборов данных» и настройте сопоставление:
    • Источник связи: ваш первый набор (таблица периодов).
    • Приемник связи: ваш подчиненный набор (запрос к оборотам).
    • Выражение источника: поле начала месяца (например, НачалоПериода).
    • Выражение приемника: поле начала периода из подчиненного запроса.
    • Параметр: укажите имя созданного параметра СвязьНачПериода.
    Повторите аналогичную настройку для связи по конечной дате периода с параметром СвязьКонПериода.

Важное предупреждение о производительности: Связывание наборов данных через передачу параметров в виртуальные таблицы СУБД на уровне платформы преобразуется в выполнение отдельных запросов в цикле. Если в отчете будет выбрана периодичность «День» за год, система выполнит 365 отдельных тяжелых запросов к базе данных, что приведет к катастрофическому падению скорости формирования отчета. Рассмотрим более оптимальные альтернативы.

---

Решение №2. Использование динамической периодичности в одном запросе

Если перед нами стоит задача предоставить пользователю возможность динамически менять периодичность отчета (День, Месяц, Квартал, Год) и при этом мы хотим обойтись одним эффективным запросом, мы можем использовать конструкцию ВЫБОР КОГДА в тексте запроса СКД.

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


ВЫБРАТЬ
    ВЫБОР &Период
        КОГДА "День" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, ДЕНЬ)
        КОГДА "Месяц" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, МЕСЯЦ)
        КОГДА "Год" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, ГОД)
    КОНЕЦ КАК ПериодНачало,
    ВЫБОР &Период
        КОГДА "День" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, ДЕНЬ)
        КОГДА "Месяц" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, МЕСЯЦ)
        КОГДА "Год" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, ГОД)
    КОНЕЦ КАК ПериодКонец,
    ХозрасчетныйОбороты.Субконто1 КАК Статья,
    СУММА(ХозрасчетныйОбороты.СуммаОборот) КАК СуммаОборот
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Обороты(&НачПериода, &КонПериода, Регистратор, , , , , ) КАК ХозрасчетныйОбороты

СГРУППИРОВАТЬ ПО
    ХозрасчетныйОбороты.Субконто1,
    ВЫБОР &Период
        КОГДА "День" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, ДЕНЬ)
        КОГДА "Месяц" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, МЕСЯЦ)
        КОГДА "Год" ТОГДА НАЧАЛОПЕРИОДА(ХозрасчетныйОбороты.Период, ГОД)
    КОНЕЦ,
    ВЫБОР &Период
        КОГДА "День" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, ДЕНЬ)
        КОГДА "Месяц" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, МЕСЯЦ)
        КОГДА "Год" ТОГДА КОНЕЦПЕРИОДА(ХозрасчетныйОбороты.Период, ГОД)
    КОНЕЦ

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

---

Решение №3. Периодичность «Авто» в виртуальной таблице

Наиболее лаконичным и платформенным решением для получения корректных итогов по периодам является использование значения Авто в параметре периодичности виртуальной таблицы. Посмотрим, как это упрощает логику запроса:


ВЫБРАТЬ
    ХозрасчетныйОбороты.Субконто1 КАК Статья,
    ХозрасчетныйОбороты.Организация КАК Организация,
    ХозрасчетныйОбороты.СуммаОборот КАК СуммаОстаток,
    ХозрасчетныйОбороты.ПериодМесяц КАК ПериодМесяц,
    ХозрасчетныйОбороты.ПериодДень КАК ПериодДень
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Обороты(&НачПериода, &КонПериода, Авто, , , , , ) КАК ХозрасчетныйОбороты

При использовании ключевого слова Авто виртуальная таблица автоматически добавляет в схему компоновки данных все возможные поля периодов: ПериодСекунда, ПериодМинута, ПериодЧас, ПериодДень, ПериодНеделя, ПериодДекада, ПериодМесяц, ПериодКвартал, ПериодПолугодие, ПериодГод, а также поля Регистратор и НомерСтроки.

После этого вам достаточно в настройках структуры отчета (на вкладке «Настройки» в СКД) добавить группировку по нужному вам полю (например, по ПериодМесяц). Система самостоятельно оптимизирует SQL-запрос под выбранную группировку, и вы получите корректные помесячные обороты без дублирования годовых сумм.

---

Решение №4. Механизм «Дополнение периодов» в СКД

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

Рассмотрим, как его настроить:

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

Теперь платформа самостоятельно сгенерирует дополняющие строки с нулевыми показателями для тех месяцев, по которым в базе данных не было зарегистрировано движений. Это избавит вас от необходимости проектирования сложных запросов-календарей.

---

Резюме и рекомендации

Подведем итог. Если вы столкнулись с тем, что СКД выводит годовой итог вместо помесячного, это верный признак того, что у вас включено автозаполнение, а связь между наборами данных по стандартным параметрам нарушена.

Для простых отчетов с фиксированным периодом мы рекомендуем использовать Решение №3 (периодичность Авто). Для отчетов, где требуется гарантированный вывод пустых месяцев, идеальным выбором будет Решение №4 (дополнение периодов силами СКД). К созданию двух наборов данных и ручной настройке параметров связи (Решение №1) следует прибегать только в исключительных случаях, помня о возможных проблемах с производительностью на больших объемах данных.

← На главную