При разработке аналитических отчетов часто возникает задача развернуть показатели (например, объем отгрузки, количество заявок или звонков) по часам суток в виде кросс-таблицы: в строках выводятся дни и документы, а в колонках — каждый час суток от 00:00 до 23:00. Разберем основные способы решения этой задачи в платформе 1С:Предприятие.
При попытке жестко задать список времени через литералы дат разработчики часто сталкиваются с тем, что значение ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0) выводится в консоли запросов как пустая строка. Выясним причину такого поведения.
В платформе 1С дата 01.01.0001 00:00:00 считается пустой датой (аналог NULL или неопределенного момента времени). По умолчанию платформа форматирует пустое значение даты как пустую строку. Если же указать хотя бы одну секунду или час, например ДАТАВРЕМЯ(1, 1, 1, 1, 0, 0), платформа воспринимает значение как заполненную дату и выводит ее целиком: 01.01.0001 01:00:00.
Поскольку в 1С нет отдельного типа данных «Время» (время всегда привязано к дате), работать с часами можно несколькими путями:
0 до 23.Если цель заключается в группировке существующих документов по часам, нет необходимости генерировать искусственные даты. Достаточно извлечь номер часа с помощью встроенной функции языка запросов ЧАС() или получить начало часа через НАЧАЛОПЕРИОДА().
Посмотрим на пример запроса, выбирающего данные по заявкам:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Заявка.Дата, ДЕНЬ) КАК День,
Заявка.Ссылка КАК Заявка,
ЧАС(Заявка.Дата) КАК НомерЧаса,
Заявка.Объем КАК Объем
ИЗ
Документ.ЗаявкаНаПоставкуПродукции КАК Заявка
ГДЕ
Заявка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
В этом запросе поле НомерЧаса вернет целое число от 0 до 23, по которому удобно группировать колонки кросс-таблицы.
Если отчет строится без использования СКД и требуется гарантированно получить все 24 часа (даже если данных за эти часы нет), сформируем временную таблицу часов. Сделать это можно через объединение строк или с помощью декартова произведения.
Рассмотрим вариант с явным перечислением номеров часов и их строковых представлений:
ВЫБРАТЬ 0 КАК НомерЧаса, "00:00" КАК ПредставлениеЧаса ПОМЕСТИТЬ ВТ_СеткаЧасов
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1, "01:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2, "02:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3, "03:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 4, "04:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 5, "05:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 6, "06:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 7, "07:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 8, "08:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 9, "09:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 10, "10:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 11, "11:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 12, "12:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 13, "13:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 14, "14:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 15, "15:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 16, "16:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 17, "17:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 18, "18:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 19, "19:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 20, "20:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 21, "21:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 22, "22:00"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 23, "23:00"
;
ВЫБРАТЬ
Сетка.ПредставлениеЧаса КАК Час,
ЕСТЬNULL(СУММА(Данные.Объем), 0) КАК Объем
ИЗ
ВТ_СеткаЧасов КАК Сетка
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаявкаНаПоставкуПродукции КАК Данные
ПО Сетка.НомерЧаса = ЧАС(Данные.Дата)
И Данные.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
СГРУППИРОВАТЬ ПО
Сетка.ПредставлениеЧаса,
Сетка.НомерЧаса
УПОРЯДОЧИТЬ ПО
Сетка.НомерЧаса
Важный момент: при левом соединении для отсутствующих значений функция ЕСТЬNULL() позволяет заменить NULL на 0, чтобы избежать пустых ячеек при суммировании.
Если отчет создается на Системе компоновки данных (СКД), генерировать искусственные таблицы вручную не требуется. Платформа умеет автоматически заполнять недостающие периоды.
Разберем по шагам, как построить кросс-таблицу по часам в СКД:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Заявка.Дата, ДЕНЬ) КАК ПериодДень,
НАЧАЛОПЕРИОДА(Заявка.Дата, ЧАС) КАК ПериодЧас,
Заявка.Ссылка КАК Заявка,
Заявка.Объем КАК Объем
ИЗ
Документ.ЗаявкаНаПоставкуПродукции КАК Заявка
ГДЕ
Заявка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
ПериодЧас в колонке Роль указываем, что это период с типом Час.ПериодЧас форматную строку ДФ=ЧЧ:мм (или ДФ="ЧЧ:00"). Благодаря этому пользователь увидит аккуратные заголовки колонок вида 00:00, 01:00, ..., 23:00 без даты.Объем с выражением Сумма(Объем).ПериодДень, внутри нее — группировка по полю Заявка.ПериодЧас.ПериодЧас, переходим во вкладку Дополнительно (или свойства группировки), устанавливаем флаг Дополнять период, выбираем тип периода Час и указываем границы дополнения (начало и конец дня).При таком подходе СКД автоматически выведет все 24 колонки для каждого дня, даже если заявки оформлялись только в определенные часы.