有没有办法在这个表中的GROUP BY时间间隔?

时间:2011-09-27 15:31:05

标签: sql sql-server-2008 group-by

我有一张像这样的表:

DateTime   A

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

这可以创建一个每10秒返回A平均值的查询吗?在这种情况下,结果将是:

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

提前致谢!

编辑:如果你真的认为这不能做,那就说不管! :)这是一个可以接受的答案,我真的不知道是否可以这样做。

EDIT2:我正在使用SQL Server 2008.我希望有不同的分组但是已修复。例如,范围每10秒,1分钟,5分钟,30分钟,1小时和1天(只是一个例子,但类似的东西)

6 个答案:

答案 0 :(得分:4)

在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

答案 1 :(得分:2)

这取决于您使用的DBMS。 在Oracle中,您可以执行以下操作:

SELECT AVG(A) 
FROM MYTABLE 
GROUP BY to_char(DateTime, 'HH24:MI') 

答案 2 :(得分:1)

有人可能会给你一个完整代码的答案,但我采用的方法是将其分解为几个较小的问题/解决方案:

(1)创建一个包含间隔的临时表。请参阅此问题的接受答案:

Get a list of dates between two dates

这个答案是针对MySQL的,但应该让你入门。谷歌搜索“创建间隔SQL”也应该产生其他方法来实现这一目标。您将需要使用主表中的MAX(日期时间)和MIN(日期时间)作为您使用的任何方法的输入(显然,跨度为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 

编辑如果您想查看没有记录的间隔(零平均值),则必须重新启动查询,在m.A上使用LEFT JOIN和COALESCE(参见下文)。如果你不关心看到这样的内部,那么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 

答案 3 :(得分:1)

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)

答案 4 :(得分:1)

我通过使用公用表表达式来获取此数据,以获取数据的任何给定日期之间的所有时间段。原则上,您可以将间隔更改为任何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)

答案 5 :(得分:0)

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's answer因为我知道那里发生了什么,并且我能够在6个月内理解它而不再重新审视它,但我完整地包含了这个。