SQL如何在时间段内分组
Posted
技术标签:
【中文标题】SQL如何在时间段内分组【英文标题】:SQL how to group in time periods 【发布时间】:2011-10-18 02:23:32 【问题描述】:我正在尝试按时间段对数据进行分组。每个时间段为 5 分钟,我想看看从 08:00 到 18:00 每 5 分钟发生的情况。
我创建了一个表格,其中包含该时间范围内的所有时间段。例如:
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 - 但我不确定这是否正确。直觉告诉我,这与分析服务有关。
谢谢
【问题讨论】:
我认为这只是意味着您在 08:45 到 08:50 之间有 4 个活动。你想输出什么? 对不起,5 分钟。请看更新 【参考方案1】:注意 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: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】:您说您想对结果进行分组,但您没有将GROUP
应用于查询。
但是,如果您汇总结果,您将丢失您也想要的独特信息(Description
、StartDate
),除非它们与组中的其他记录匹配。
正如 Scorpi0 所评论的,您想要的输出样本会很有用。
【讨论】:
因此您实际上并不需要GROUP BY
查询,您希望查看所有时间范围,即使没有任何活动。因此,似乎 Scorpi0 的答案会为您提供所需的东西。但是,当每个“时间组”多于一行时会发生什么?
嗨托尼。是的,我想查看一段时间内的所有活动。如果有不止一个活动,那么我希望在每一行中看到所有活动和重复的时间段。【参考方案3】:
您在活动表上有一个过滤器: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)
【讨论】:
您好,感谢您的回复。我已经进行了更改,并且得到了相同的结果... 看起来第一个查询应该可以解决问题。你确定不是吗,vikp?【参考方案4】:您需要将活动时间条件从常见的 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
【讨论】:
"A >= B and A以上是关于SQL如何在时间段内分组的主要内容,如果未能解决你的问题,请参考以下文章