Есть ли способ, чтобы GROUP BY временной интервал в этой таблице? - PullRequest
3 голосов
/ 27 сентября 2011

У меня есть такая таблица:

DateTime   A

10:00:01   2 
10:00:07   4
10:00:10   2
10:00:17   1
10:00:18   3

Можно ли создать запрос, который возвращает мне среднее значение A каждые 10 секунд?В этом случае результат будет:

3 (4+2)/2
2 (2+1+3)/3

Заранее спасибо!

РЕДАКТИРОВАТЬ: Если вы действительно думаете, что это не может быть сделано, просто скажите НЕТ!:) Это приемлемый ответ, я действительно не знаю, можно ли это сделать.

EDIT2: я использую SQL Server 2008. Я хотел бы иметь разные группировки, но исправленные.Например, диапазоны каждые 10 секунд, 1 минута, 5 минут, 30 минут, 1 час и 1 день (просто пример, но что-то в этом роде)

Ответы [ 6 ]

4 голосов
/ 27 сентября 2011

В SQL Server вы можете использовать DATEPART, а затем группировать по часам, минутам и секундам с целочисленным делением 10.

CREATE TABLE #times
(
    thetime time,
    A int
)

INSERT #times
VALUES ('10:00:01', 2)
INSERT #times
VALUES ('10:00:07', 4)
INSERT #times
VALUES ('10:00:10', 2)
INSERT #times
VALUES ('10:00:17', 1)
INSERT #times
VALUES ('10:00:18', 3)

SELECT avg(A)    --   <-- here you might deal with precision issues if you need non-integer results.  eg:  (avg(a * 1.0)
FROM #times
GROUP BY datepart(hour, thetime), DATEPART(minute, thetime), DATEPART(SECOND, thetime) / 10

DROP TABLE #times
2 голосов
/ 27 сентября 2011

Это зависит от используемой вами СУБД. В Oracle вы можете сделать следующее:

SELECT AVG(A) 
FROM MYTABLE 
GROUP BY to_char(DateTime, 'HH24:MI') 
1 голос
/ 01 февраля 2013

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

DECLARE @interval_minutes INT = 5, @start_date DATETIME = '20130201', @end_date DATETIME = GETDATE()

;WITH cte_period AS
 (
    SELECT  CAST(@start_date AS DATETIME) AS [date]

    UNION ALL

     SELECT DATEADD(MINUTE, @interval_minutes, cte_period.[date]) AS [date]
     FROM cte_period
     WHERE DATEADD(MINUTE, @interval_minutes, cte_period.[date]) < @end_date
 )

, cte_intervals AS
 (SELECT [first].[date] AS [Start], [second].[date] AS [End] 
 FROM cte_period [first] 
 LEFT OUTER JOIN cte_period [second] ON DATEADD(MINUTE, 5, [first].[date]) = [second].[date]
  )

SELECT i.[Start], AVG(data)
FROM cte_intervals i
LEFT OUTER JOIN your_data mu ON mu.your_date_time >= i.Start and mu.your_date_time < i.[End]
GROUP BY i.[Start]
OPTION (MAXRECURSION 0)
1 голос
/ 27 сентября 2011
CREATE TABLE IF NOT EXISTS `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `dtime` datetime NOT NULL,
  `val` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;


INSERT INTO `test` (`id`, `dtime`, `val`) VALUES
(1, '2011-09-27 18:36:19', 8),
(2, '2011-09-27 18:36:21', 4),
(3, '2011-09-27 18:36:27', 5),
(4, '2011-09-27 18:36:35', 3),
(5, '2011-09-27 18:36:37', 2);

SELECT *, AVG(val) FROM test GROUP BY FLOOR(UNIX_TIMESTAMP(dtime) / 10)
1 голос
/ 27 сентября 2011

Кто-то может прийти и дать вам ответ с полным кодом, но я бы поделился с этим, разбив его на несколько более мелких проблем / решений:

(1) Создать временную таблицу с интервалами. Смотрите принятый ответ на этот вопрос:

Получить список дат между двумя датами

Этот ответ был для MySQL, но вы должны начать. Поиск в Google «Создание интервалов SQL» также должен дать дополнительные способы для достижения этой цели. Вы захотите использовать MAX (DateTime) и MIN (DateTime) из основной таблицы в качестве входных данных для любого метода, который вы используете (и 10 секунд для диапазона, очевидно).

(2) Соединить временную таблицу с основной таблицей с условием соединения (псевдокод):

FROM mainTable m INNER JOIN #tempTable t ON m BETWEEN t.StartDate AND t.EndDate

(3) Теперь это должно быть так же просто, как правильно ВЫБРАТЬ и Сгруппировать:

SELECT 
  AVG(m.A)     
FROM  
  mainTable m 
  INNER JOIN #tempTable t ON m BETWEEN t.StartDate AND t.EndDate 
GROUP BY 
  t.StartDate 

Редактировать: , если вы хотите видеть интервалы, в которых нет записей (среднее нулевое значение), вам придется изменить порядок запроса, использовать LEFT JOIN и COALESCE для m.A (см. Ниже). Если вас не интересует видение таких элементов, решение OCary лучше / чище.

SELECT 
  AVG(COALESCE(m.A, 0))
FROM  
  #tempTable t
  LEFT JOIN mainTable m ON m BETWEEN t.StartDate AND t.EndDate 
GROUP BY 
  t.StartDate 
0 голосов
/ 07 декабря 2015

С http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=142634 вы также можете использовать следующий запрос:

select dateadd(minute, datediff(minute, 0, timestamp ) / 10 * 10, 0), avg ( value )
from   yourtable
group by dateadd(minute, datediff(minute, 0, timestamp ) / 10 * 10, 0)

, который затем кто-то расширит, чтобы предложить:

Select
a.MyDate,
Start_of_10_Min =
dateadd(mi,(datepart(mi,a.MyDate)/10)*10,dateadd(hh,datediff(hh,0,a.Mydate),0))
from
( -- Test Data
select MyDate = getdate()
) a

, хотя я нетакже, как они планируют получить среднее значение во втором предложении.

Лично я предпочитаю ответ OCary , поскольку я знаю, что там происходит, и что я смогу понять это в6 месяцев, не просматривая его снова, но я включаю этот для полноты.

...