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

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

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

Способ 1. Использование временной таблицы с готовыми интервалами

Один из самых простых и гибких способов — заранее подготовить список всех необходимых временных слотов и передать их в запрос. Проанализируем этот подход: мы создаем таблицу значений в коде 1С, заполняем её нужными интервалами (08:00, 08:10, 08:20 и так далее), а затем передаем в запрос как параметр.

Разберем пример реализации в программном коде:


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

ТекущееВремя = НачалоДня(ВыбраннаяДата) + 8 * 3600; // Начинаем с 08:00
Пока ТекущееВремя < (НачалоДня(ВыбраннаяДата) + 20 * 3600) Цикл
    НоваяСтрока = ТЗ_Интервалы.Добавить();
    НоваяСтрока.НачалоИнтервала = ТекущееВремя;
    ТекущееВремя = ТекущееВремя + 600; // Добавляем 10 минут
    НоваяСтрока.КонецИнтервала = ТекущееВремя;
КонецЦикла;

В самом запросе мы используем ЛЕВОЕ СОЕДИНЕНИЕ этой временной таблицы с нашими данными (например, документами «Звонок»). Условие соединения будет выглядеть так: Данные.Дата >= ВтИнтервалы.НачалоИнтервала И Данные.Дата < ВтИнтервалы.КонецИнтервала. Это гарантирует, что каждый звонок попадет в свой временной слот.

Способ 2. Генерация последовательности интервалов внутри запроса

Если мы не хотим передавать внешние данные, можно сгенерировать сетку времени прямо в теле запроса. Для этого используется техника декартова произведения маленьких таблиц с числами. Рассмотрим ситуацию, когда нам нужно получить 144 десятиминутных интервала (сутки).

Сначала создадим временную таблицу Цифры, содержащую значения от 0 до 9. Соединив её саму с собой, мы получим последовательности 0–99, 0–999 и т.д. Эти числа мы будем использовать как смещение в минутах от начала дня.


ВЫБРАТЬ 0 КАК Цифра ПОМЕСТИТЬ ВТ_Цифры ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1 ... ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 9;

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

Этот метод позволяет получить чистую таблицу периодов без обращения к метаданным или внешним наборам данных. После формирования ВТ_Сетка мы соединяем её с основной таблицей документов.

Способ 3. Математическое округление времени

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

Рассмотрим формулу для 10-минутного интервала (600 секунд):

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

Способ 4. Использование механизма «ПЕРИОДАМИ» и СКД

Если основной целью является построение отчета, то наиболее правильным решением будет использование Системы компоновки данных (СКД). В СКД существует встроенный механизм дополнения периодов. Проанализируем ситуацию: если в 08:10 звонков не было, обычный запрос просто пропустит эту строку, и в отчете возникнет «дырка».

Чтобы этого избежать:

  1. В схеме компоновки данных на закладке «Наборы данных» выберите поле Дата.
  2. В колонке «Роль» укажите, что это «Период».
  3. В настройках отчета (вкладка «Группировки») для этого поля установите тип дополнения «День», «Час» или «Минута».

Однако для интервала именно в 10 минут стандартного дополнения в СКД нет. В этом случае мы возвращаемся к Способу 1 или Способу 2, создавая «скелет» отчета из всех интервалов, и левым соединением добавляем к нему реальные данные документов.

Способ 5. Создание оборотного регистра накопления

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

Рассмотрим алгоритм работы с регистром:

  1. При проведении документа «Запись звонка» мы программно определяем, к какому интервалу относится событие.
  2. Записываем данные в регистр, где одним из измерений является Интервал (например, справочник или перечисление со значениями «08:00», «08:10»...).
  3. В отчете мы просто обращаемся к виртуальной таблице Обороты этого регистра. Это максимально быстрый способ получения данных, так как вся сложная логика расчета интервалов выполняется один раз в момент записи документа, а не каждый раз при формировании отчета.

Важные нюансы: границы интервалов

Проанализируем критически важный момент — обработку пограничных значений времени. Если звонок начался ровно в 08:10:00, в какой интервал он должен попасть: в «08:00–08:10» или в «08:10–08:20»? Чтобы избежать дублирования данных или их потери, всегда придерживайтесь правила: включаем начало и исключаем конец.

В запросе это реализуется строгим неравенством для верхней границы:

ГДЕ Документ.Дата >= Интервал.Начало И Документ.Дата < Интервал.Конец

Использование МЕЖДУ в данном случае является ошибкой, так как оно включает обе границы, и событие на стыке минут может задвоиться в отчете.

Таким образом, выбор метода зависит от ваших задач. Для разового простого отчета подойдет Способ 1 с передачей таблицы значений. Для сложной аналитической панели с высокой нагрузкой лучше реализовать Способ 5 с регистрами накопления. А для динамического формирования сетки внутри кода без лишних объектов метаданных идеально подходит Способ 2.

← На главную