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