При построении аналитических отчетов, особенно графиков плотности продаж или активности склада, разработчики часто сталкиваются с проблемой «пустых» периодов. Если в определенный интервал времени (например, с 10:15 до 10:30) не было зарегистрировано ни одного документа, этот интервал просто исчезает из выборки запроса. В результате график «схлопывается», соединяя точки 10:00 и 10:30 прямой линией, что искажает реальную картину спада активности. Рассмотрим подробно, как решить эту задачу с помощью формирования временной сетки и правильного соединения таблиц.
Когда мы пишем простой запрос к таблице документов Документ.ЧекККМ или Документ.РеализацияТоваровУслуг, система выбирает только те данные, которые физически существуют в базе данных. Если записей за 15-минутку нет, то и строки в результате запроса не будет. Для системы компоновки данных (СКД) или обычного построителя отчетов это означает отсутствие точки на оси времени.
Чтобы увидеть «ноль», нам необходимо сначала создать «эталонную» таблицу, содержащую абсолютно все интервалы времени за нужный период, а уже к ней «приклеивать» реальные данные из документов. Проанализируем, как это реализовать технически.
Этот метод считается классическим для запросов в 1С. Мы вручную или программно создаем таблицу, в которой перечислены все часы и все четверти часа (00, 15, 30, 45 минут). Рассмотрим пример построения такой сетки для рабочего дня с 09:00 до 20:45.
Сначала сформируем таблицу часов:
ВЫБРАТЬ "09" КАК Часы ПОМЕСТИТЬ ВТ_ВремяЧасы
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "10"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "11"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "12"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "13"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "14"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "15"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "16"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "17"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "18"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "19"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "20";
Затем создадим таблицу минут для 15-минутных интервалов:
ВЫБРАТЬ ":00" КАК Минуты ПОМЕСТИТЬ ВТ_ВремяМинуты
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ":15"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ":30"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ":45";
Теперь объединим их с помощью перекрестного соединения (Декартова произведения), чтобы получить полную сетку времени дня:
ВЫБРАТЬ
ВТ_ВремяЧасы.Часы + ВТ_ВремяМинуты.Минуты КАК ЧасыСМинутами
ПОМЕСТИТЬ ВТ_Периоды
ИЗ
ВТ_ВремяЧасы КАК ВТ_ВремяЧасы,
ВТ_ВремяМинуты КАК ВТ_ВремяМинуты;
Чтобы соединить реальные чеки с нашей сеткой, нам нужно привести время каждого документа к формату сетки (округлить до ближайшей 15-минутки «вниз»). Для этого используем конструкцию ВЫБОР. Проанализируем ситуацию на примере:
ВЫБРАТЬ
ВЫБОР
КОГДА МИНУТА(Чеки.Дата) < 15 ТОГДА ":00"
КОГДА МИНУТА(Чеки.Дата) < 30 ТОГДА ":15"
КОГДА МИНУТА(Чеки.Дата) < 45 ТОГДА ":30"
ИНАЧЕ ":45"
КОНЕЦ КАК Минуты,
ФОРМАТ(ЧАС(Чеки.Дата), "ЧГ=0") КАК Часы,
Чеки.СуммаДокумента КАК Сумма,
Чеки.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_ДанныеДокументов
ИЗ
Документ.ЧекККМ КАК Чеки
ГДЕ
НАЧАЛОПЕРИОДА(Чеки.Дата, ДЕНЬ) = &ВыбДата
И Чеки.ПометкаУдаления = ЛОЖЬ;
Самый важный этап — соединение. Мы должны использовать ЛЕВОЕ СОЕДИНЕНИЕ, где ведущей таблицей будет наша сетка ВТ_Периоды. Если данных в документах нет, функция ЕСТЬNULL поможет нам превратить пустоту в заветный ноль.
ВЫБРАТЬ
ВТ_Периоды.ЧасыСМинутами КАК Период,
СУММА(ЕСТЬNULL(ВТ_ДанныеДокументов.Сумма, 0)) КАК СуммаРеализации,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВТ_ДанныеДокументов.Ссылка) КАК КоличествоДокументов
ИЗ
ВТ_Периоды КАК ВТ_Периоды
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДанныеДокументов КАК ВТ_ДанныеДокументов
ПО (ВТ_ДанныеДокументов.Часы + ВТ_ДанныеДокументов.Минуты = ВТ_Периоды.ЧасыСМинутами)
СГРУППИРОВАТЬ ПО
ВТ_Периоды.ЧасыСМинутами
УПОРЯДОЧИТЬ ПО
Период;
Если вам нужно вывести плотность документов не просто в целом, а в разрезе складов, обычное левое соединение может работать некорректно. Если по Складу №2 не было движений весь день, он может вообще не попасть в отчет. Чтобы этого избежать, используйте «размножение» сетки:
ВТ_Периоды на таблицу складов (Декартово произведение). Вы получите полную матрицу «Каждый период — Каждый склад».Период и Склад.Тогда в графике по каждому складу будут честные нули в те моменты, когда продаж не было, и график отобразит реальный спад.
В современной платформе 1С 8.3 для решения этой задачи лучше использовать Систему компоновки данных. Рассмотрим, как это сделать без написания сложных запросов с объединениями:
Период (или создайте вычисляемое поле с округлением до 15 минут).Вместо громоздких конструкций ВЫБОР КОГДА для определения 15-минутки, можно использовать математический трюк в запросе:
ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(Чеки.Дата, ДЕНЬ), СЕКУНДА, ЦЕЛОЕ(РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(Чеки.Дата, ДЕНЬ), Чеки.Дата, СЕКУНДА) / 900) * 900)
Здесь мы вычисляем количество секунд, прошедших с начала дня, делим на 900 (это 15 минут в секундах), отбрасываем дробную часть и умножаем обратно на 900. Это дает нам универсальный инструмент для группировки по любому количеству минут.
Таким образом, мы рассмотрели несколько способов решения задачи. Выбор конкретного метода зависит от сложности вашего отчета и используемых инструментов визуализации. Помните, что для корректного графика в 1С наличие строки с нулевым значением является обязательным условием.