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