2014-10-28 4 views
0

У меня есть таблица архивов в моей БД, которая содержит миллионы пар datetime/value. Теперь мне нужно сделать эти данные доступными на веб-странице, используя диаграмму javascript.Получить агрегированные данные, указав переменный временной интервал

Из-за огромного объема данных мне нужно реализовать какую-то ленивую загрузку и агрегацию данных. На стороне клиента все уже работает отлично (с имитированными агрегированными данными) - чего не хватает на SQL-запрос на серверной стороне, который передает данные.

Чтобы быть точным: мне интересно, как запрашивать данные, указав переменную величину времени (например, в минутах), где результат дает мне минимальное, максимальное и среднее значение для этого интервала.

В настоящее время я использую этот код, который дает мне необходимые данные на почасовой основе:

SELECT CAST(DATEADD(hour,FLOOR(DATEDIFF(hour,0,CAST(DateValue AS datetime))),0) as datetime) as d, avg(Value) as Av, min(Value) as Mn, max(Value) as Mx 
    FROM [TESTDB].[dbo].[ValueArchive] 
    WHERE StationId=5 and DataPointId=21507 
    GROUP BY CAST(DATEADD(hour,FLOOR(DATEDIFF(hour,0,CAST(DateValue AS datetime))),0) as datetime) 
    order by d 

Этот запрос возвращает данные, как это:

Zeit     Av     Mn     Mx 
2014-07-31 07:00:00.000 21,5311364673079 21,1000043854118 22,0000043988228 
2014-07-31 08:00:00.000 21,5188868579348 21,0000043839216 22,0000043988228 
2014-07-31 09:00:00.000 21,5014227301436 10,3    21,9000043973327 
2014-07-31 10:00:00.000 21,6056305272473 21,1000043854118 22,200004401803 
2014-07-31 11:00:00.000 21,7478380172488 21,300004388392  22,200004401803 
2014-07-31 12:00:00.000 21,9086686573894 21,5000043913722 22,4000044047833 
2014-07-31 13:00:00.000 22,6290701521411 21,7000043943524 25,2000044465065 
2014-07-31 14:00:00.000 24,3890669344227 23,7000044241548 25,1000044450164 
2014-07-31 15:00:00.000 23,5097663260819 23,000004413724  24,0000044286251 
2014-07-31 16:00:00.000 23,3656704604484 22,9000044122338 23,900004427135 
2014-07-31 17:00:00.000 23,3113943797538 22,9000044122338 23,8000044256449 
2014-07-31 18:00:00.000 23,3023299996241 22,8000044107437 23,8000044256449 
2014-07-31 19:00:00.000 23,3033443003657 22,8000044107437 23,8000044256449 
2014-07-31 20:00:00.000 23,265605921441  22,7000044092536 23,8000044256449 
2014-07-31 21:00:00.000 23,1962274382304 22,7000044092536 23,8000044256449 
2014-07-31 22:00:00.000 23,0771869545565 22,6000044077635 23,5000044211745 
2014-07-31 23:00:00.000 22,9476058889577 22,200004401803  23,5000044211745 
2014-08-01 00:00:00.000 22,7839329819327 22,3000044032931 23,2000044167042 
2014-08-01 01:00:00.000 22,6155113662449 22,0000043988228 23,1000044152141 
2014-08-01 02:00:00.000 22,4463981676577 21,9000043973327 22,9000044122338 

Это хороший старт, но я не знаю, как изменить этот запрос таким образом, чтобы он работал с интервалами, такими как 2 минуты, 15 минут или 5 секунд и т. д. Даты начала/окончания интервалов должны быть выровнены с полным часом, так что если вы запрашиваете 10-минутные интервалы для заданного временного диапазона, блоки данных должны содержать данные с 10:00 до 10:10, от 10:10 до 10:20 и т. д. (Это квантование важно при работе с дополнительными независимыми рядами данных, которые используют одну и ту же ось времени x).

Есть ли способ достичь этой функциональности непосредственно в БД с помощью запроса (или хранимой процедуры)? Или мне сначала нужно получить все данные, а затем выполнить агрегацию на веб-сервере?

Благодарим за помощь!

ответ

1

Поскольку целочисленное деление в SQL Server возвращает целое число, вы можете получить разницу во времени между вашим DateValue и некоторой эпохой, делить это на ваш интервал и повторно умножить его на ваш интервал и преобразовать результат обратно в datetime. Это приведет к выравниванию ваших интервалов с часом (при условии, что вы используете значения, которые разделяют равномерно, 7 секундных интервалов не будут выровнены, но, например, 5 секунд). В ниже я использую минуты, но это тривиально, чтобы изменить его использовать секунды:

declare @interval_minutes int = 15 
select dateadd(MINUTE, DATEDIFF(MINUTE, '01-jan-1970', DateValue)/@interval_minutes*@interval_minutes, '01-jan-1970') as d 
     avg(Value) as Av, 
     min(Value) as Mn, 
     max(Value) as Mx 
FROM [TESTDB].[dbo].[ValueArchive] 
WHERE StationId=5 and DataPointId=21507 
group by DATEDIFF(MINUTE, '01-jan-1970', DateValue)/@interval_minutes 

В качестве примера этого SQL:

declare @interval_minutes int = 15 
select dateadd(MINUTE, DATEDIFF(MINUTE, '01-jan-1970', getdate())/@interval_minutes*@interval_minutes, '01-jan-1970') as d 

вернется 2014-10-28 13:15:00.000, когда я запускаю его в 13:23 на 28 окт.

Изменение интервала до 30 дает 2014-10-28 13:00:00.000.

Смежные вопросы