Как правильно реализовать группировку данных по дням в запросах 1С?

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

При разработке отчетов и аналитических запросов программисты часто сталкиваются с необходимостью объединения записей за конкретные календарные сутки. Несмотря на кажущуюся простоту, здесь существует множество нюансов: от выбора правильной функции преобразования даты до выбора между физическими и виртуальными таблицами. В этой статье мы подробно разберем, как корректно суммировать данные по дням, избегая типичных ошибок, которые приводят к неверным результатам или низкой производительности системы.

Анализ проблемы: почему данные не суммируются?

Рассмотрим типичную ситуацию: у нас есть РегистрНакопления.Продажи. Каждая запись в нем имеет точное время (час, минута, секунда). Если мы просто попытаемся выполнить СГРУППИРОВАТЬ ПО Период, система не объединит продажи за один день, так как для нее время 12:00:00 и 15:00:00 — это разные значения. В итоге мы получим столько же строк, сколько было в исходной таблице, но без детальной информации.

Многие начинающие разработчики пытаются использовать конструкцию ИТОГИ ПЕРИОДАМИ. Важно понимать: эта секция предназначена для построения иерархических структур (дерева) и автоматического дополнения периодов. Если ваша задача — просто получить плоскую таблицу со сгруппированными данными, использование ИТОГИ избыточно и может привести к путанице при обходе результата запроса.

Решение 1: Группировка с помощью функции НАЧАЛОПЕРИОДА

Самый простой и наглядный способ сгруппировать данные — привести все значения времени к началу дня (00:00:00). Для этого в языке запросов 1С предусмотрена функция НАЧАЛОПЕРИОДА. Давайте проанализируем правильный код запроса:


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

Важные моменты этого подхода:

  1. Мы используем функцию НАЧАЛОПЕРИОДА как в списке выбора, так и в секции СГРУППИРОВАТЬ ПО. Это критически важно: группировка должна происходить именно по результату функции, а не по исходному полю.
  2. Для числовых данных (ресурсов) мы обязательно применяем агрегатную функцию СУММА.
  3. Не используйте функцию ДЕНЬ(Дата) для этих целей. Функция ДЕНЬ() возвращает лишь число месяца (от 1 до 31). Это приведет к тому, что продажи за 1 марта и 1 апреля схлопнутся в одну строку, что в корне неверно для большинства отчетов.

Решение 2: Использование виртуальной таблицы Обороты

Работа с физической таблицей регистра (как в первом решении) допустима только на небольших объемах данных. Для высоконагруженных систем правильным подходом является использование виртуальной таблицы .Обороты. Проанализируем, почему это эффективнее:

Система 1С хранит предварительно рассчитанные итоги. Когда мы обращаемся к виртуальной таблице, платформа не пересчитывает все записи с начала времен, а берет уже готовые агрегаты. Чтобы получить группировку по дням, нам достаточно указать параметр Периодичность.

Рассмотрим пример кода:


ВЫБРАТЬ
    ПродажиОбороты.Период КАК Дата,
    ПродажиОбороты.КоличествоОборот КАК Количество,
    ПродажиОбороты.ВыручкаОборот КАК Выручка
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, День, ) КАК ПродажиОбороты

В данном случае нам даже не требуется секция СГРУППИРОВАТЬ ПО, так как виртуальная таблица сама сворачивает данные согласно выбранной периодичности День. Поле Период в результате такого запроса автоматически будет содержать дату начала дня.

Сравнение методов и оптимизация

Выясним, какой метод выбрать в конкретной ситуации. Если вы строите сложный запрос, где продажи соединяются с другими таблицами по сложным условиям, иногда удобнее использовать НАЧАЛОПЕРИОДА. Однако в 90% случаев использование виртуальной таблицы Обороты будет работать быстрее.

Рассмотрим нюансы оптимизации:

  1. Фильтрация: Если вам нужно отобрать данные по конкретной номенклатуре или складу, делайте это в параметрах виртуальной таблицы (четвертый параметр "Условие"). Это значительно ускоряет выполнение, так как СУБД отсекает лишние записи на раннем этапе.
  2. Пустые дни: Если за какой-то день не было движений, виртуальная таблица (и обычная группировка) просто не вернет эту строку. Если в отчете должны быть все даты (например, с 1 по 10 число), используйте механизм дополнения периодов в Системе компоновки данных (СКД) или соединение с временной таблицей-календарем.
  3. Избыточность кода: Если вы используете виртуальную таблицу с периодичностью День, не нужно дополнительно вызывать НАЧАЛОПЕРИОДА в блоке ВЫБРАТЬ. Это создает лишнюю вычислительную нагрузку.

Особенности работы в СКД

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

  1. На вкладке "Наборы данных" для поля Период укажите роль "Период" с типом "День".
  2. В настройках отчета добавьте группировку по полю Период.
  3. Установите тип дополнения "День", чтобы система сама отрисовала даты, в которые не было продаж.

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

Подводя итог, отметим: для простых задач используйте РегистрНакопления.Продажи.Обороты(,, День). Если же вам необходимо работать с физическими таблицами или нестандартными источниками данных, применяйте СГРУППИРОВАТЬ ПО НАЧАЛОПЕРИОДА(ПолеДата, ДЕНЬ). Эти подходы гарантируют корректность суммирования ресурсов и высокую скорость работы вашего приложения.

← На главную