При разработке отчетов периодически возникает задача сгруппировать данные и получить итоги с детализацией по неделям, месяцам или другим интервалам времени. Разработчики нередко сталкиваются с ситуацией, когда один и тот же синтаксис запроса с конструкцией ИТОГИ ПО Период ПЕРИОДАМИ(НЕДЕЛЯ, ...) прекрасно работает для виртуальных таблиц регистров, но при обращении к физическим таблицам документов начинает выводить строки с точностью до каждой секунды.
Разберем детально, почему так происходит, как устроен механизм дополнения периодов в платформе 1С:Предприятие и какими способами можно правильно сгруппировать данные по неделям.
Проанализируем исходный запрос к виртуальной таблице оборотов регистра накопления, который отрабатывает ожидаемо:
ВЫБРАТЬ
ЗаправкиТопливаТСОбороты.Период КАК Период,
ЗаправкиТопливаТСОбороты.СтоимостьОборот,
ЗаправкиТопливаТСОбороты.КоличествоОборот
ИЗ
РегистрНакопления.ЗаправкиТопливаТС.Обороты(&ДатаНачала, &ДатаОкончания, НЕДЕЛЯ, ) КАК ЗаправкиТопливаТСОбороты
СГРУППИРОВАТЬ ПО
ЗаправкиТопливаТСОбороты.Период,
ЗаправкиТопливаТСОбороты.СтоимостьОборот,
ЗаправкиТопливаТСОбороты.КоличествоОборот
ИТОГИ ПО
Период ПЕРИОДАМИ(НЕДЕЛЯ, &ДатаНачала, &ДатаОкончания)
АВТОУПОРЯДОЧИВАНИЕ
А теперь посмотрим на аналогичный запрос к таблице документов:
ВЫБРАТЬ
уатПутевойЛист.Дата КАК Период,
уатПутевойЛист.Ссылка КАК Документ,
уатПутевойЛист.Контрагент КАК Контрагент
ИЗ
Документ.уатПутевойЛист КАК уатПутевойЛист
ГДЕ
уатПутевойЛист.Дата МЕЖДУ &Начало И &Окончание
СГРУППИРОВАТЬ ПО
уатПутевойЛист.Дата,
уатПутевойЛист.Контрагент,
уатПутевойЛист.Ссылка
ИТОГИ ПО
Период ПЕРИОДАМИ(НЕДЕЛЯ, &Начало, &Окончание)
АВТОУПОРЯДОЧИВАНИЕ
Причина такого поведения заключается в назначении секции ПЕРИОДАМИ и различиях в исходных типах данных:
НЕДЕЛЯ в параметры виртуальной таблицы Обороты, сама платформа 1С автоматически приводит поле Период к началу недели (понедельник, 00:00:00). Поэтому все записи изначально имеют одинаковые даты начала недель.Дата документа является физическим полем типа Дата со временем (с точностью до секунды). Поскольку каждая дата уникальна, группировка в секции ИТОГИ ПО Период создает отдельную строку для каждой секунды проведения документа.Для того чтобы запрос по таблице документов корректно сформировал итоги по неделям, необходимо явно рассчитать дату начала недели с помощью функции НАЧАЛОПЕРИОДА и именно по ней выполнять расчет итогов.
Рассмотрим исправленный вариант запроса:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(уатПутевойЛист.Дата, НЕДЕЛЯ) КАК НачалоНедели,
уатПутевойЛист.Дата КАК Период,
уатПутевойЛист.Ссылка КАК Документ,
уатПутевойЛист.Контрагент КАК Контрагент
ИЗ
Документ.уатПутевойЛист КАК уатПутевойЛист
ГДЕ
уатПутевойЛист.Дата МЕЖДУ &Начало И &Окончание
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(уатПутевойЛист.Дата, НЕДЕЛЯ),
уатПутевойЛист.Дата,
уатПутевойЛист.Контрагент,
уатПутевойЛист.Ссылка
ИТОГИ ПО
НачалоНедели ПЕРИОДАМИ(НЕДЕЛЯ, &Начало, &Окончание)
АВТОУПОРЯДОЧИВАНИЕ
В этом случае платформа сгруппирует документы по началу каждой недели, а пропущенные недели (где не было документов) будут сгенерированы автоматически благодаря указанию ПЕРИОДАМИ(НЕДЕЛЯ, &Начало, &Окончание).
Важно помнить, как платформа 1С возвращает дополненные периоды при выполнении запроса:
Результат.Выгрузить() возвращает плоскую таблицу без дополненных пустых периодов. Чтобы получить иерархию со всеми периодами, следует использовать метод Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам) для выгрузки в ДеревоЗначений."ВСЕ" в метод Выбрать:
ВыборкаПериод = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "НачалоНедели", "ВСЕ");
Пока ВыборкаПериод.Следующий() Цикл
// Вывод шапки недели
ОбластьНеделя.Параметры.Заполнить(ВыборкаПериод);
ТабДок.Вывести(ОбластьНеделя, ВыборкаПериод.Уровень);
// Выборка детальных записей внутри недели
ВыборкаДетали = ВыборкаПериод.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
ОбластьСтрока.Параметры.Заполнить(ВыборкаДетали);
ТабДок.Вывести(ОбластьСтрока, ВыборкаДетали.Уровень);
КонецЦикла;
КонецЦикла;
Если отчет разрабатывается на базе СКД, использовать секцию ИТОГИ в тексте запроса не требуется вовсе. СКД берет на себя задачу дополнения периодов через визуальные настройки:
НАЧАЛОПЕРИОДА(уатПутевойЛист.Дата, НЕДЕЛЯ) КАК ПериодНеделя.ПериодНеделя указываем роль Период и выставляем порядковый номер.ПериодНеделя. В свойствах группировки находим параметр Тип дополнения и устанавливаем значение Неделя, а также указываем начальную и конечную дату дополнения.Система компоновки данных самостоятельно заполнит пропущенные недели даже при полном отсутствии движений за выбранный диапазон дат.
Когда требуется сформировать плоский список недель без создания иерархических группировок (например, для передачи во внешнюю систему или выгрузки в плоскую таблицу значений), формируют генератор интервалов через соединение с производственным календарем:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Календарь.Дата, НЕДЕЛЯ) КАК ПериодНеделя
ПОМЕСТИТЬ ВТ_Недели
ИЗ
РегистрСведений.ПроизводственныйКалендарь КАК Календарь
ГДЕ
Календарь.Дата МЕЖДУ &Начало И &Окончание
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(Календарь.Дата, НЕДЕЛЯ)
;
ВЫБРАТЬ
ВТ_Недели.ПериодНеделя КАК ПериодНеделя,
уатПутевойЛист.Ссылка КАК Документ,
уатПутевойЛист.Контрагент КАК Контрагент
ИЗ
ВТ_Недели КАК ВТ_Недели
ЛЕВОЕ СОЕДИНЕНИЕ Документ.уатПутевойЛист КАК уатПутевойЛист
ПО ВТ_Недели.ПериодНеделя = НАЧАЛОПЕРИОДА(уатПутевойЛист.Дата, НЕДЕЛЯ)
И уатПутевойЛист.Дата МЕЖДУ &Начало И &Окончание
УПОРЯДОЧИТЬ ПО
ПериодНеделя
Такой подход гарантирует наличие всех недель в результирующей таблице даже при выгрузке через обычный РезультатЗапроса.Выгрузить().