Как расчесать период по месяцам в запросе 1С

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

В практике разработки на платформе 1С часто возникает задача «расчесать» или детализировать заданный период (например, между двумя датами) на отдельные составляющие — чаще всего на месяцы. Это необходимо для построения отчетов, где нужно показать данные даже за те периоды, в которых не было фактических движений в регистрах. Разберем основные способы решения этой задачи: от стандартных механизмов запроса до хитростей с перемножением таблиц и настроек системы компоновки данных.

Метод 1: Использование конструкции ПЕРИОДАМИ в секции ИТОГИ

Это самый быстрый способ дополнения дат, предусмотренный языком запросов 1С. Рассмотрим ситуацию: нам нужно получить количество продаж, но при этом гарантировать, что в выборку попадут все месяцы интервала, даже если продаж в них не было. Проанализируем пример кода:


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

Важная особенность: Как было отмечено в ходе обсуждения, ключевое слово ПЕРИОДАМИ работает исключительно при обходе результата запроса через объект ВыборкаИзРезультатаЗапроса. Если вы попытаетесь выгрузить результат такого запроса в ТаблицаЗначений методом Выгрузить(), пустые периоды в таблицу не попадут. Этот метод идеально подходит для вывода данных в иерархический список на форме или формирования печатной формы через обход выборки.

Метод 2: Использование производственного календаря

Если разработка ведется в типовой конфигурации (например, 1С:Зарплата и Управление Персоналом или 1С:ERP), мы можем воспользоваться готовыми данными системы. В таких конфигурациях есть регистр сведений ДанныеПроизводственногоКалендаря. Давайте выясним, как получить из него список месяцев:

  1. Выбираем все записи из регистра за нужный период.
  2. Фильтруем по конкретному производственному календарю (например, "РФ").
  3. Группируем результат по началу месяца.

Рассмотрим пример запроса:


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

Полученную таблицу можно поместить во временную таблицу (ПОМЕСТИТЬ ВТ_Месяцы) и далее использовать ее для ЛЕВОЕ СОЕДИНЕНИЕ с вашими основными данными (например, с регистром накопления). Это обеспечит наличие строки для каждого месяца в итоговом результате.

Метод 3: Генерация периодов через «Таблицу чисел» (Универсальный)

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

1. Создадим временную таблицу из 10 цифр (от 0 до 9) с помощью объединения запросов. Это наш «базис».

2. Перемножим эту таблицу саму на себя (Cross Join) несколько раз, чтобы получить последовательность от 0 до 99, 999 или более.

3. Прибавим полученное число месяцев к начальной дате периода.

Проанализируем пример формирования такой таблицы:


ВЫБРАТЬ 0 КАК Цифра ПОМЕСТИТЬ Цифры ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2 
// ... и так далее до 9
;

ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, т1.Цифра + т2.Цифра * 10 + т3.Цифра * 100) КАК ПериодМесяц
ПОМЕСТИТЬ ВТ_ВсеПериоды
ИЗ
    Цифры КАК т1,
    Цифры КАК т2,
    Цифры КАК т3
ГДЕ
    ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, т1.Цифра + т2.Цифра * 10 + т3.Цифра * 100) <= &ДатаОкончания

Этот метод гарантированно работает на любой платформе и конфигурации, так как не зависит от наличия данных в базе. Мы фактически «вычисляем» таблицу периодов «на лету».

Метод 4: Дополнение периодов в СКД

Если задача стоит в рамках создания отчета на Системе компоновки данных (СКД), то «расчесывание» периодов можно делегировать самому механизму компоновки. Это зачастую проще и эффективнее, чем писать сложные запросы.

Для реализации дополнения выполним следующие действия:

  1. В схеме компоновки данных на вкладке "Наборы данных" выберем поле, отвечающее за период (например, ПериодМесяц).
  2. В колонке "Роль" нажмем на кнопку редактирования и убедимся, что указан тип периода (например, Месяц).
  3. В настройках отчета (вкладка "Настройки" -> "Выбранные поля" или в настройках конкретной группировки) для этого поля установим Тип дополнения — Месяц.
  4. Укажем Начало периода и Конец периода (обычно это параметры отчета &НачалоПериода и &КонецПериода).

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

Метод 5: Передача готовой таблицы из кода

Иногда проще сформировать список дат в модуле на языке 1С и передать его в запрос как параметр. Посмотрим, как это выглядит:


ТЗПериодов = Новый ТаблицаЗначений;
ТЗПериодов.Колонки.Добавить("Период", Новый ОписаниеТипов("Дата"));

ТекущаяДата = НачалоМесяца(Объект.ДатаНачала);
Пока ТекущаяДата <= Объект.ДатаОкончания Цикл
    НоваяСтрока = ТЗПериодов.Добавить();
    НоваяСтрока.Период = ТекущаяДата;
    ТекущаяДата = ДобавитьМесяц(ТекущаяДата, 1);
КонецЦикла;

Запрос.УстановитьПараметр("ТЗПериодов", ТЗПериодов);

Затем в самом запросе мы используем конструкцию ВЫБРАТЬ * ИЗ &ТЗПериодов КАК ТЗПериодов. Это позволяет избежать сложной логики генерации дат внутри SQL-запроса и сделать код более читаемым для других разработчиков.

Подведем итог: выбор метода зависит от контекста. Для простых отчетов используйте ИТОГИ ПЕРИОДАМИ или механизмы СКД. Для сложных расчетных задач, где периоды нужны внутри временных таблиц запроса, лучше всего подойдет использование производственного календаря или универсальный метод с перемножением таблиц цифр.

← На главную