我在SQL Server中有一个表来存储一块硬件的统计信息,表中的行表示给定秒的数据。它包含例如这些列:
timestamp (DateTime)
value (int)
我想要做的是从表格中选择给定日期/时间范围的数据,但是以给定时间段(例如1分钟,5分钟,1天等)的平均值返回在给定范围之间。所以一小时我有60行1分钟的平均值。
我从哪里开始?有人有什么意见或想法吗?
答案 0 :(得分:9)
您可以在时间戳的DatePart上进行选择和分组。
例如:
SELECT
DATEPART(hh, [timestamp]),
DATEPART(mi, [timestamp]),
AVG([value])
FROM
YourTable
WHERE
[timestamp] BETWEEN '2009-01-01 00:00:00.000' AND '2009-02-01 00:00:00.000'
GROUP BY
DATEPART(hh, [timestamp]),
DATEPART(mi, [timestamp])
编辑:对于更复杂的时间跨度,如5分钟,您可以按照以下方式对日期部分进行除法。
DATEPART(mi, [timestamp]) / 5 * 5
答案 1 :(得分:5)
WITH cal(m) AS
(
SELECT 1
UNION ALL
SELECT m + 1
FROM cal
WHERE m < 60
)
SELECT DATEADD(minute, m, @start), AVG(value)
FROM cal
LEFT JOIN
timestamp
ON timestamp > DATEADD(minute, m, @start)
AND timestamp <= DATEADD(minute, m + 1, @start)
GROUP BY
m
这将选择给定小时内所有分钟的平均值,即使是那些没有记录的分钟。
答案 2 :(得分:1)
除了Robin Day的帖子之外,你可以按照5分钟的间隔进行分组,如:
GROUP BY
DATEPART(hh, [timestamp]),
DATEPART(mi, [timestamp]) / 5
如果您想延长几天,请参加dy,一年中的一天:
GROUP BY
DATEPART(dy, [timestamp]),
DATEPART(hh, [timestamp]),
DATEPART(mi, [timestamp]) / 5
答案 3 :(得分:1)
如果您要为此数据提供较高的读/写比率,则可能需要考虑索引视图。我已经在整个地方使用这种方法来按时间段聚合。我刚到blogging the example,这是代码:
create table timeSeries (
timeSeriesId int identity primary key clustered
,updateDate datetime not null
,payload float not null
)
insert timeSeries values ('2009-06-16 12:00:00', rand())
insert timeSeries values ('2009-06-16 12:00:59', rand())
insert timeSeries values ('2009-06-16 12:01:00', rand())
insert timeSeries values ('2009-06-16 12:59:00', rand())
insert timeSeries values ('2009-06-16 01:00:00', rand())
insert timeSeries values ('2009-06-16 1:30:00', rand())
insert timeSeries values ('2009-06-16 23:59:00', rand())
insert timeSeries values ('2009-06-17 00:01:00', rand())
insert timeSeries values ('2009-06-17 00:01:30', rand())
create view timeSeriesByMinute_IV with schemabinding as
select
dayBucket = datediff(day, 0, updateDate)
,minuteBucket = datediff(minute, 0, (updateDate - datediff(day, 0, updateDate)))
,payloadSum = sum(payLoad)
,numRows = count_big(*)
from dbo.timeSeries
group by
datediff(day, 0, updateDate)
,datediff(minute, 0, (updateDate - datediff(day, 0, updateDate)))
go
create unique clustered index CU_timeSeriesByMinute_IV on timeSeriesByMinute_IV (dayBucket, minuteBucket)
go
create view timeSeriesByMinute as
select
dayBucket
,minuteBucket
,payloadSum
,numRows
,payloadAvg = payloadSum / numRows
from dbo.timeSeriesByMinute_IV with (noexpand)
go
declare @timeLookup datetime, @dayBucket int, @minuteBucket int
select
@timeLookup = '2009-06-16 12:00:00'
,@dayBucket = datediff(day, 0, @timeLookup)
,@minuteBucket = datediff(minute, 0, (@timeLookup - datediff(day, 0, @timeLookup)))
select * from timeSeriesByMinute where dayBucket = @dayBucket and minuteBucket = @minuteBucket
您可以在代码块的末尾看到示例查找。显然,您可以定义要查询的范围,而不是仅仅寻找特定的dayBucket / minuteBucket对。
答案 4 :(得分:1)
如果没有以下更改,我无法得到Quassnoi的工作答案:
WITH cal(m) AS
(
SELECT 1
UNION ALL
SELECT m + 1
FROM cal
WHERE m < 60
)
SELECT DATEADD(minute, m, @start) m, AVG(value)
FROM cal
LEFT JOIN
YourTable
ON timestamp > DATEADD(minute, m, @start)
AND timestamp <= DATEADD(minute, m + 1, @start)
GROUP BY
m