При построении отчетов с детализацией по месяцам за период в несколько лет разработчики часто сталкиваются с задачей разделения одинаковых месяцев разных лет (например, март 2023 и март 2024 года). Если сгруппировать данные только по функции МЕСЯЦ(Период), данные за разные годы объединятся в один общий месяц. Разберем основные и наиболее эффективные способы корректной группировки, нумерации и форматирования периодов в языке запросов, СКД и программном коде 1С.
Рассмотрим самый надежный, производительный и рекомендуемый стандарт платформы 1С для группировки данных по месяцам. Функция НАЧАЛОПЕРИОДА приводит любую дату к первому числу соответствующего месяца со временем 00:00:00.
Посмотрим на практический пример запроса к регистру накопления:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ) КАК МесяцПериода,
Продажи.Номенклатура КАК Номенклатура,
СУММА(Продажи.СуммаОборот) КАК Сумма
ИЗ
РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаКонца, Авто, ) КАК Продажи
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ),
Продажи.Номенклатура
УПОРЯДОЧИТЬ ПО
МесяцПериода
Проанализируем преимущества этого подхода:
Дата, что сохраняет встроенные механизмы сортировки и фильтрации.01.03.2023 00:00:00) автоматически будет меньше марта 2024 года (01.03.2024 00:00:00), упорядочивание сработает идеально.Если источником данных является виртуальная таблица регистра (например, Обороты или ОстаткиИОбороты), платформа 1С предоставляет встроенные средства группировки периодов.
Разберем два варианта настройки периодичности:
Месяц. В этом случае системное поле Период уже будет представлять собой дату начала месяца.Авто в списке доступных полей виртуальной таблицы появляются готовые поля: ПериодСекунда, ПериодДень, ПериодМесяц, ПериодКвартал, ПериодГод. Достаточно выбрать ПериодМесяц без использования дополнительных функций.
ВЫБРАТЬ
Продажи.ПериодМесяц КАК ПериодМесяц,
Продажи.Номенклатура КАК Номенклатура,
Продажи.КоличествоОборот КАК Количество
ИЗ
РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаКонца, Авто, ) КАК Продажи
В некоторых задачах (например, для экспорта данных, интеграций через JSON/XML или специфических вычислений) требуется получить период в виде целого числа. Разберем, как правильно составить формулу и почему частые решения на форумах содержат ошибку.
Ошибочный вариант: МЕСЯЦ(Период) * 10000 + ГОД(Период). При такой формуле март 2024 года превратится в число 32024, а декабрь 2023 года — в 122023. При сортировке декабрь 2023 окажется позже марта 2024, что нарушит порядок данных.
Правильный вариант: Формирование числа в формате ГГГГММ:
ВЫБРАТЬ
ГОД(Затраты.Период) * 100 + МЕСЯЦ(Затраты.Период) КАК КодПериодаЧислом,
СУММА(Затраты.Сумма) КАК Сумма
ИЗ
РегистрНакопления.Затраты КАК Затраты
СГРУППИРОВАТЬ ПО
ГОД(Затраты.Период) * 100 + МЕСЯЦ(Затраты.Период)
В данном случае март 2024 года станет числом 202403, а декабрь 2023 — 202312. Числовая сортировка полностью совпадает с хронологической.
Если требуется получить сквозной порядковый номер месяца с начала летоисчисления или от конкретной точки отсчета, воспользуемся функцией РАЗНОСТЬДАТ.
ВЫБРАТЬ
РАЗНОСТЬДАТ(ДАТАВРЕМЯ(1, 1, 1), Затраты.Период, МЕСЯЦ) КАК НомерМесяцаОтНачала,
СУММА(Затраты.Сумма) КАК Сумма
ИЗ
РегистрНакопления.Затраты КАК Затраты
СГРУППИРОВАТЬ ПО
РАЗНОСТЬДАТ(ДАТАВРЕМЯ(1, 1, 1), Затраты.Период, МЕСЯЦ)
Обратим внимание на производительность: не рекомендуется использовать вычисляемые выражения с РАЗНОСТЬДАТ, МЕСЯЦ или ГОД в секции ГДЕ (условиях фильтрации) запроса. Такие конструкции приводят к блокировке использования индексов СУБД и вызывают полное сканирование таблицы (Table Scan). Для фильтрации всегда передавайте точные граничные даты: Период МЕЖДУ &ДатаНачала И &ДатаКонца.
Если отчет разрабатывается с использованием СКД, писать дополнительные вычисления в тексте запроса не требуется.
Период.Период и в типе дополнения периода выбираем Месяц.ДФ='ММММ гггг' — отобразит дату в виде «Март 2024».ДФ=MM.yyyy — отобразит дату в виде «03.2024».ДФ='кв. К гггг' — отобразит дату в виде «кв. 1 2024».В программном коде конфигурации для работы с месяцами и датами предусмотрен богатый набор встроенных функций платформы:
// Приведение даты к первому числу месяца
ДатаМесяца = НачалоМесяца(ТекущаяДата());
// Форматирование для вывода пользователю
ПредставлениеПериода = Формат(ТекущаяДата(), "ДФ='ММММ гггг'"); // Например, "Март 2024"
// Расчет количества месяцев между двумя датами
КоличествоМесяцев = (Год(ДатаКонца) - Год(ДатаНачала)) * 12 + (Месяц(ДатаКонца) - Месяц(ДатаНачала));
// Смещение даты на заданное число месяцев
СледующийПериод = ДобавитьМесяц(ДатаМесяца, 1);
Подведем итог: для отчетов и группировок в запросах всегда отдавайте предпочтение функции НАЧАЛОПЕРИОДА(Период, МЕСЯЦ) с последующим форматированием в представлении. Это гарантирует максимальную производительность базы данных и корректное хронологическое упорядочивание записей.