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