Média-T SQL Tempo
-
05-07-2019 - |
Pergunta
Eu tenho uma tabela no SQL Server que armazena estatísticas para uma peça de hardware, linhas na tabela representam os dados para um determinado segundo. Ele contém, por exemplo, estas colunas:
timestamp (DateTime)
value (int)
O que eu quero fazer é selecionar os dados da tabela para uma determinada data / intervalo de tempo, mas devolvê-lo de tal maneira a que as médias para um período de tempo determinado (tal como 1 minuto, 5 minutos, um dia etc) entre o intervalo dado. Então, por uma hora eu teria 60 linhas de médias 1 minuto.
Onde posso começar com isso? Qualquer pessoa quaisquer pontos ou idéias?
Solução
Você pode fazer um seleto e GROUP BY em um PartData do seu timestamp.
Por exemplo:
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])
EDIT:. Para seus intervalos de tempo mais complexos como 5 minutos, você pode fazer uma divisão na datepart como segue
DATEPART(mi, [timestamp]) / 5 * 5
Outras dicas
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
Isso irá selecionar médias para todos os minutos dentro de uma determinada hora, mesmo aqueles para os quais não há registros.
Além da mensagem por Robin Day, você pode agrupar por intervalos de 5 minutos como:
GROUP BY
DATEPART(hh, [timestamp]),
DATEPART(mi, [timestamp]) / 5
E se você gostaria de abranger vários dias, o grupo de dy, para o dia do ano:
GROUP BY
DATEPART(dy, [timestamp]),
DATEPART(hh, [timestamp]),
DATEPART(mi, [timestamp]) / 5
Se você estiver indo para ter uma alta taxa de leitura / gravação para esses dados você pode querer considerar uma exibição indexada. Eu tenho usado essa abordagem em todo o lugar para agregada por baldes de tempo. Eu só cheguei a blogging o exemplo , aqui está o código:
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
Você pode ver o exemplo de pesquisa no final do bloco de código. É claro que você pode definir intervalos para consulta em vez de apenas procurando um determinado par dayBucket / minuteBucket.
Eu não poderia obter a resposta de Quassnoi ao trabalho sem as seguintes alterações:
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