2013-06-04 2 views
1

Рассмотрим следующие две таблицы:TSQL GROUP BY без агрегации

key_names 
---------------------------------------------- 
id | name 
---------------------------------------------- 
1 Outside Temperature 
2 Inside Temperature 
3 Relative Humidity 

key_values 
---------------------------------------------- 
id | time     | key_id | value 
---------------------------------------------- 
1 2013-06-04 13:20:16.347 1  50 
2 2013-06-04 13:20:16.348 2  30 
3 2013-06-04 13:20:16.349 3  10 
4 2013-06-04 13:20:31.120 1  55 
5 2013-06-04 13:20:31.122 2  29 
6 2013-06-04 13:20:31.120 3  11 

Значения записываются в базу данных на 15-секундными интервалами для 3-х различных ключей. Я хочу, чтобы вытащить значения через 1 минуту, 5 минут, 1 час и другие интервалы.

Это то, что я прямо сейчас за пять минут интервала:

SELECT time, key_name, value 
FROM key_values kv 
JOIN key_names kn ON kv.key_id = kn.id 
WHERE (key_id = 1 OR key_id = 2 OR key_id = 3) 
    AND time >= '2013-06-04 12:20:30' 
    AND time < '2013-06-04 13:20:30' 
GROUP BY DATEPART(YEAR, time), DATEPART(MONTH, time), DATEPART(DAY, time), 
    DATEPART(HOUR, time), (DATEPART(MINUTE, time)/5), kv.key_id, kn.key_name 
ORDER BY kv.time DESC 

Конечно, этот запрос будет давать мне следующую ошибку:

Column 'key_values.time' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Но я не хотите какие-либо агрегированные данные! Мне просто нужны фактические значения для строк с пятиминутным интервалом. Как я могу исправить этот запрос?

Ожидаемый результат Set: (в течение 5-минутного интервала)

---------------------------------------------------- 
time    | key_id | value 
---------------------------------------------------- 
2013-06-04 13:20:16 1  50 
2013-06-04 13:20:16 2  30 
2013-06-04 13:20:16 3  10 
2013-06-04 13:15:16 1  ... 
2013-06-04 13:15:16 2  ... 
2013-06-04 13:15:16 3  ... 
2013-06-04 13:10:16 1  ... 
2013-06-04 13:10:16 2  ... 
2013-06-04 13:10:16 3  ... 
...     ...  ... 

Для одного из парней, отвечая на мой вопрос:

SELECT time, key_name, value 
FROM (
     SELECT time, key_name, value, ROW_NUMBER() over (partition by convert(varchar(16), time, 121) order by time desc) as seqnum 
     FROM key_values kv 
     JOIN key_names kn ON kn.id = kv.tag_id 
     WHERE (key_id = 1 OR key_id = 2) 
       AND time >= '2013-06-04 12:20:30' AND time < '2013-06-04 13:20:30' 
) k 
where seqnum = 1; 


Its only returning one of the keys.. 

2013-06-04 12:20:59.577 Outside Temperature  45 
2013-06-04 12:21:59.607 Outside Temperature  45 
2013-06-04 12:22:59.637 Outside Temperature  45 
2013-06-04 12:23:59.687 Outside Temperature  45 
2013-06-04 12:24:59.697 Outside Temperature  46 
2013-06-04 12:25:59.723 Outside Temperature  46 
+0

Хорошо, вы можете показать, что вы на самом деле хотите в качестве вывода? –

+0

Хорошо. Я добавил ожидаемый набор результатов. –

ответ

5

Вы хотите использовать функцию row_number() для перечисления значений в каждом интервале. Затем просто возьмите последний или первый - в зависимости от того, хотите ли вы последний раз перед интервалом или первым перед ним.

Ниже приведен пример для 1-минутного интервала:

select time, key_name, value 
from (SELECT time, key_name, value, 
      ROW_NUMBER() over (partition by key_name, convert(varchar(16), time, 121) order by time desc) as seqnum 
     FROM key_values kv join 
      key_names kn 
      ON kv.key_id = kn.id 
    ) k 
where seqnum = 1; 

Выражения convert(varchar(16), time, 121) форматирование даты с точностью до минуты (с использованием усечения).

EDIT: Другие приращения. В следующем примере показано, как сделать это для пролетов 15 минут:

(partition by key_name, datediff(minute, 0, time)/15 order by . . .) 

Для 5 минут с шагом использовать 5 вместо 15 и так далее. Это вычисляет количество минут с начала времени (с поддержкой базы данных). SQL Server выполняет целочисленное деление, поэтому деление на целое создает идентификатор временного интервала. Для других устройств вы можете заменить minute на hour, second, day, month, или year.

Для первоначального запроса я понял, что convert() было легче понять.

+0

Много новых ключевых слов и функций, чтобы узнать об этом в ответ. Мне нравится! Это не совсем так, как я ожидал, пожалуйста, посмотрите это пасти: http://pastebin.com/X2X6ShAB –

+0

@ChrisG. , , , Этот сайт фактически заблокирован, где я; можете ли вы описать проблему или вставить ее в свой вопрос? –

+0

Я положил это на мой вопрос, ура! –

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