SQL как группировать по периодам времени - PullRequest
1 голос
/ 02 августа 2011

Я пытаюсь сгруппировать данные по периодам времени. Каждый период длится 5 минут, и я хотел бы видеть, что происходит каждые 5 минут с 08:00 до 18:00.

Я создал таблицу, в которой есть все периоды времени в этом диапазоне времени. E.g.:

StartTime           EndTime             IsBusinessHours
08:40:00.0000000    08:45:00.0000000    1
08:45:00.0000000    08:50:00.0000000    1
08:50:00.0000000    08:55:00.0000000    1
08:55:00.0000000    09:00:00.0000000    1

и т.д.

Select 
    TimeDimension.[StartTime],
    TimeDimension.[EndTime],
    activity.[Description],
    activity.[StartTime]
From
    TimeDimension 
    Full Outer Join Activity 
       on (
              Convert(varchar,activity.StartTime,108) >= Convert(varchar,TimeDimension.starttime, 108) 
          And Convert(varchar,activity.StartTime,108) <= Convert(varchar,TimeDimension.endtime, 108)
       )
Where               
    activity.Date = @DateParam 
And TimeDimension.isbusinesshours = 1

Я ожидаю, что данные будут сгруппированы по 5-минутным периодам времени, но я получаю:

08:20:00.0000000    08:25:00.0000000 Some activity
08:30:00.0000000    08:35:00.0000000 Some activity
08:45:00.0000000    08:50:00.0000000 Three activities in this time period. First
08:45:00.0000000    08:50:00.0000000 Three activities in this time period. Second 
08:45:00.0000000    08:50:00.0000000 Three activities in this time period. Third

Когда я бы хотел увидеть:

08:20:00.0000000    08:25:00.0000000 Some activity
08:25:00.0000000    08:30:00.0000000 NULL
08:30:00.0000000    08:35:00.0000000 Some activity
08:35:00.0000000    08:40:00.0000000 NULL
08:45:00.0000000    08:50:00.0000000 Three activities in this time period. First
08:45:00.0000000    08:50:00.0000000 Three activities in this time period. Second 
08:45:00.0000000    08:50:00.0000000 Three activities in this time period. Third

Это означает, что я отображаю периоды времени, когда имели место некоторые действия, а не все периоды времени в этом диапазоне. Я назвал таблицу TimeDimension - но я не уверен, что это правильно. Чутье говорит мне, что это как-то связано с аналитическими службами.

Спасибо

Ответы [ 4 ]

4 голосов
/ 02 августа 2011

Примечание 1: Выполнение арифметики DATETIME с использованием VARCHAR приводит к низкой производительности.

Примечание 2: У вас есть OUTER JOIN, но затем предложение WHERE, которое не учитывает NULL.


Это то, что я бы использовал ...

WITH
  FilteredActivity AS
(
  SELECT
    Description,
    DATEADD(DAY, -DATEDIFF(DAY, 0, StartTime), StartTime) AS StartTime
  FROM
    Activity
  WHERE
    Date = @DateParam
)

SELECT
  TimeDimension.[StartTime],
  TimeDimension.[EndTime],
  activity.[Description],
  activity.[StartTime]
FROM
  TimeDimension
LEFT JOIN
  FilteredActivity AS [Activity]
    ON  Activity.StartTime >= TimeDimension.StartTime
    AND Activity.StartTime <  TimeDimension.EndTime
WHERE
  TimeDimension.isbusinesshours = 1


Фильтрация CTE

  • CTE при запуске фильтрует активность до одной даты
  • Это позволяет избежать условия в предложении WHERE, которое плохо работает с OUTER JOINs


Форматирование CTE

  • CTE также сокращает StartTime до просто TimePart
  • Бизнес DATEADD / DATEDIFF необходим, только если StartTime также включает DATE
  • Если это уже время, просто используйте StartTime


Эксклюзив против EndTime Inclusive

  • У меня есть < EndTime вместо <= EndTime
  • Это предполагает интервалы в виде 08:00 to 08:05 и 08:05 to 08:10 и т. Д.
  • ИмеяEndTime как «первый раз, когда вы не хотите включать», может упростить задачу
  • Больше нет округления Activity.StartTime до ближайшей минуты, например
  • И никаких странных интервалов 08:00 to 08:04 и т. Д.


Альтернативой использованию исключительных значений EndTime является округление значений Activity.StartTime до ближайшей минуты.Вместо того, чтобы использовать строки, следующее делает это, используя функции DateTime ...
- DATEADD(minute, DATEDIFF(minute, 0, Activity.StartTime), 0)

2 голосов
/ 02 августа 2011

Вы говорите, что хотите сгруппировать результаты, но не применяете GROUP к запросу.

Однако, если вы агрегируете результаты, вы потеряете нужную вам информацию (Description, StartDate), если они не соответствуют другим записям в группе.

Как прокомментировал Scorpi0, полезный пример выходных данных.

1 голос
/ 02 августа 2011

Вам необходимо переместить условие времени активности из общего условия Where в условие Join , например:

Select 
    TimeDimension.[StartTime],
    TimeDimension.[EndTime],
    activity.[Description],
    activity.[StartTime]
From
    TimeDimension 
    Full Outer Join Activity 
       on (
              Convert(varchar,activity.StartTime,108) >= Convert(varchar,TimeDimension.starttime, 108) 
          And Convert(varchar,activity.StartTime,108) <= Convert(varchar,TimeDimension.endtime, 108)
And activity.Date = @DateParam
       )
Where               
    TimeDimension.isbusinesshours = 1
1 голос
/ 02 августа 2011

У вас есть фильтр в таблице активности: activity.Date = @DateParam.

Он не позволяет получить каждую строку таблицы TimeDimension.Поместите фильтр в предложение объединения, и вы увидите все свои данные.

Select 
    TimeDimension.[StartTime],
    TimeDimension.[EndTime],
    activity.[Description],
    activity.[StartTime]
From
    TimeDimension 
    Full Outer Join Activity 
       on (
              Convert(varchar,activity.StartTime,108) >= Convert(varchar,TimeDimension.starttime, 108) 
          And Convert(varchar,activity.StartTime,108) <= Convert(varchar,TimeDimension.endtime, 108)
          And activity.Date = @DateParam 
       )
Where TimeDimension.isbusinesshours = 1

Или вы также можете сделать:

Select 
    TimeDimension.[StartTime],
    TimeDimension.[EndTime],
    activity.[Description],
    activity.[StartTime]
From
    TimeDimension 
    Full Outer Join Activity 
       on (
              Convert(varchar,activity.StartTime,108) >= Convert(varchar,TimeDimension.starttime, 108) 
          And Convert(varchar,activity.StartTime,108) <= Convert(varchar,TimeDimension.endtime, 108)
       )
Where TimeDimension.isbusinesshours = 1
And (activity.Date Is Null Or activity.Date = @DateParam)
...