SQL如何在时间段内分组

时间:2011-08-02 09:23:42

标签: sql time group-by grouping

我正在尝试按时间段对数据进行分组。每个时段都是5分钟,我想看看从08:00到18:00每5分钟发生一次。

我创建了一个包含该时间范围内所有时间段的表。 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 个答案:

答案 0 :(得分:4)

注1:使用VARCHAR执行DATETIME算法会导致性能不佳。

注意2:您有一个OUTER JOIN,但是有一个不考虑NULL的WHERE子句。


这是我用的......

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 JOIN
  • 播放效果不佳的情况


CTE格式

  • CTE还将StartTime删除为仅仅是TimePart
  • 仅当StartTime包含DATE
  • 时,才需要DATEADD / DATEDIFF业务
  • 如果已经是时间,只需使用StartTime


独家与包容性EndTime

  • 我有< EndTime而不是<= EndTime
  • 这假设时间间隔为08:00 to 08:0508:05 to 08:10
  • 将EndTime作为“第一次不想包含”可以使事情变得更容易
  • 不再舍入Activity.StartTime到最近的分钟,例如
  • 08:00 to 08:04等没有奇怪的间隔


使用Exclusive EndTime值的另一种方法是将Activity.StartTime值四舍五入到最接近的分钟。不是使用字符串,而是使用DateTime函数进行操作...
- DATEADD(minute, DATEDIFF(minute, 0, Activity.StartTime), 0)

答案 1 :(得分:2)

您说您想要对结果进行分组,但未将GROUP应用于查询。

但是,如果您汇总结果,则会丢失您想要的独特信息(DescriptionStartDate),除非它们与组中的其他记录匹配。

正如Scorpi0评论的那样,你想要的输出样本会很有用。

答案 2 :(得分:1)

活动表上有一个过滤器:activity.Date = @DateParam

它阻止获取TimeDimension表的每一行。将过滤器放在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

或者你也可以这样做:

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)

答案 3 :(得分:1)

您需要将活动时间条件从公共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