在一个时间范围内分为5分钟间隔


93

我要执行的mySQL命令有一些困难。

SELECT a.timestamp, name, count(b.name) 
FROM time a, id b 
WHERE a.user = b.user
  AND a.id = b.id
  AND b.name = 'John'
  AND a.timestamp BETWEEN '2010-11-16 10:30:00' AND '2010-11-16 11:00:00' 
GROUP BY a.timestamp

这是我当前的输出语句。

timestamp            name  count(b.name)
-------------------  ----  -------------
2010-11-16 10:32:22  John  2
2010-11-16 10:35:12  John  7
2010-11-16 10:36:34  John  1
2010-11-16 10:37:45  John  2
2010-11-16 10:48:26  John  8
2010-11-16 10:55:00  John  9
2010-11-16 10:58:08  John  2

如何将它们分为5分钟间隔结果?

我希望我的输出像

timestamp            name  count(b.name)
-------------------  ----  -------------
2010-11-16 10:30:00  John  2
2010-11-16 10:35:00  John  10
2010-11-16 10:40:00  John  0
2010-11-16 10:45:00  John  8
2010-11-16 10:50:00  John  0
2010-11-16 10:55:00  John  11 

Answers:


146

这适用于每个间隔。

PostgreSQL的

SELECT
    TIMESTAMP WITH TIME ZONE 'epoch' +
    INTERVAL '1 second' * round(extract('epoch' from timestamp) / 300) * 300 as timestamp,
    name,
    count(b.name)
FROM time a, id 
WHEREGROUP BY 
round(extract('epoch' from timestamp) / 300), name


的MySQL

SELECT
    timestamp,  -- not sure about that
    name,
    count(b.name)
FROM time a, id 
WHEREGROUP BY 
UNIX_TIMESTAMP(timestamp) DIV 300, name

哦……没有得到mysql-flag ..这是一个postgresql查询..但是基本上这也可以在mysql中实现
boecko 2010年

2
好的..而不是提取.. GROUP BY round(UNIX_TIMESTAMP(timestamp)/ 300)应该可以解决问题
boecko 2010年

2
@pHiL的注释在mySql上是正确的,您应该使用DIV而不是round(/),否则间隔之间的界限是错误的
DavidC 2013年

1
刚刚尝试了几个数据集,第二查询在MySQL方面表现出色,这是OP所关心的。由于@sky似乎不存在,因此我们是否可以就此达成共识?
乔伊T

1
我也尝试过这个。其显示的第一个记录每隔2分钟或3分钟间隔错误,再间隔5分钟,则记录错误。注意:-我添加了一个条件以获取最近15分钟的记录。
Ritesh

33

我遇到了同样的问题。

我发现按任何分钟间隔进行分组很容易,只需将纪元除以分钟(以秒为单位),然后四舍五入或使用地板取余数即可。因此,如果您希望在5分钟内获得间隔,则将使用300秒

    SELECT COUNT(*) cnt, 
    to_timestamp(floor((extract('epoch' from timestamp_column) / 300 )) * 300) 
    AT TIME ZONE 'UTC' as interval_alias
    FROM TABLE_NAME GROUP BY interval_alias
interval_alias       cnt
-------------------  ----  
2010-11-16 10:30:00  2
2010-11-16 10:35:00  10
2010-11-16 10:45:00  8
2010-11-16 10:55:00  11 

这将按选定的分钟间隔正确返回数据组。但是,它不会返回不包含任何数据的时间间隔。为了获得那些空的间隔,我们可以使用函数generate_series

    SELECT generate_series(MIN(date_trunc('hour',timestamp_column)),
    max(date_trunc('minute',timestamp_column)),'5m') as interval_alias FROM 
    TABLE_NAME

结果:

interval_alias       
-------------------    
2010-11-16 10:30:00  
2010-11-16 10:35:00
2010-11-16 10:40:00   
2010-11-16 10:45:00
2010-11-16 10:50:00   
2010-11-16 10:55:00   

现在,要获得间隔为零的结果,我们只需将两个结果集进行外部联接

    SELECT series.minute as interval,  coalesce(cnt.amnt,0) as count from 
       (
       SELECT count(*) amnt,
       to_timestamp(floor((extract('epoch' from timestamp_column) / 300 )) * 300)
       AT TIME ZONE 'UTC' as interval_alias
       from TABLE_NAME  group by interval_alias
       ) cnt
    
    RIGHT JOIN 
       (    
       SELECT generate_series(min(date_trunc('hour',timestamp_column)),
       max(date_trunc('minute',timestamp_column)),'5m') as minute from TABLE_NAME 
       ) series
  on series.minute = cnt.interval_alias

最终结果将包括具有所有5分钟间隔的系列,即使没有值的间隔也是如此。

interval             count
-------------------  ----  
2010-11-16 10:30:00  2
2010-11-16 10:35:00  10
2010-11-16 10:40:00  0
2010-11-16 10:45:00  8
2010-11-16 10:50:00  0 
2010-11-16 10:55:00  11 

通过调整generate_series的最后一个参数,可以轻松更改间隔。在我们的例子中,我们使用“ 5m”,但是它可以是我们想要的任何间隔


1
如果是MySQL,那就应该是。好像generate_series是PostgreSQL函数。太糟糕了。
Andreas

第一个查询仅给出当前数据的结果,它对两个时间段中两个时间段的中间记录进行计数。像两个时间段10:35和10:40一样,两组中的10:40都等于10:35至10:40和10:40至10:45中的一个。
Prem popatia

29

您应该宁愿使用GROUP BY UNIX_TIMESTAMP(time_stamp) DIV 300而不是round(../ 300),因为四舍五入使我发现某些记录被计入两个分组的结果集中。


这是正确的,一轮(
../300)

1
对于那些好奇的人,DIVMySQL中的sfloor()是一个浮点除法BIGINT
埃里克·L.

1
我也尝试过这个。其显示的第一个记录每隔2分钟或3分钟间隔错误,再间隔5分钟,则记录错误。注意:-我添加了一个条件以获取最近15分钟的记录。
Ritesh

应该使用TRUNCATE或FLOOR而不是ROUND,因为舍入行为没有很好的定义,并且取决于使用的C库。listing.mysql.com/mysql/93613
MrLeeh

28

对于postgres来说,我发现使用它更容易,更准确

date_trunc

功能,例如:

select name, sum(count), date_trunc('minute',timestamp) as timestamp
FROM table
WHERE xxx
GROUP BY name,date_trunc('minute',timestamp)
ORDER BY timestamp

您可以为date_trunc提供各种分辨率,例如“分钟”,“小时”,“天”等。


7
@tmarthal-不应该对其进行投票。最初的问题是针对mysql的。
buggedcom

30
您在哪里5将5分钟间隔设置在此处?
oldgod 2013年

对于上述内容,将WHERE子句更改为:WHERE timestamp> current_timestamp-间隔“ 5分钟”
Luke Smith

2
该查询似乎没有执行所要求的操作,问题是“每5分钟”而不是现在的5分钟。答案适合被downvoted
穆罕默德Rafeeq

11

查询将类似于:

SELECT 
  DATE_FORMAT(
    MIN(timestamp),
    '%d/%m/%Y %H:%i:00'
  ) AS tmstamp,
  name,
  COUNT(id) AS cnt 
FROM
  table
GROUP BY ROUND(UNIX_TIMESTAMP(timestamp) / 300), name

4

您可能需要将时间戳分解为ymd:HM并使用DIV 5将分钟分为5分钟的时间段-类似于

select year(a.timestamp), 
       month(a.timestamp), 
       hour(a.timestamp), 
       minute(a.timestamp) DIV 5,
       name, 
       count(b.name)
FROM time a, id b
WHERE a.user = b.user AND a.id = b.id AND b.name = 'John' 
      AND a.timestamp BETWEEN '2010-11-16 10:30:00' AND '2010-11-16 11:00:00'
GROUP BY year(a.timestamp), 
       month(a.timestamp), 
       hour(a.timestamp), 
       minute(a.timestamp) DIV 12

...然后以客户端代码的形式显示输出,使其以您喜欢的方式显示。或者,如果愿意,可以使用sql concat运算符来构建整个日期字符串,而不用获取单独的列。

select concat(year(a.timestamp), "-", month(a.timestamp), "-" ,day(a.timestamp), 
       " " , lpad(hour(a.timestamp),2,'0'), ":", 
       lpad((minute(a.timestamp) DIV 5) * 5, 2, '0'))

...然后再分组


嗯...但是输出没有得到我想要得到的。它返回一列,但我不太确定计数的值是多少...
sky 2010年

2

不知道您是否仍然需要它。

SELECT FROM_UNIXTIME(FLOOR((UNIX_TIMESTAMP(timestamp))/300)*300) AS t,timestamp,count(1) as c from users GROUP BY t ORDER BY t;

2016-10-29 19:35:00 | 2016-10-29 19:35:50 | 4 |

2016-10-29 19:40:00 | 2016-10-29 19:40:37 | 5 |

2016-10-29 19:45:00 | 2016-10-29 19:45:09 | 6 |

2016-10-29 19:50:00 | 2016-10-29 19:51:14 | 4 |

2016-10-29 19:55:00 | 2016-10-29 19:56:17 | 1 |


1

这个怎么样:

select 
    from_unixtime(unix_timestamp(timestamp) - unix_timestamp(timestamp) mod 300) as ts,  
    sum(value)
from group_interval 
group by ts 
order by ts
;

0

我发现使用MySQL可能正确的查询如下:

SELECT SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300,  
                                 '%Y-%m-%d %H:%i:%S' ) , 1, 19 ) AS ts_CEILING,
SUM(value)
FROM group_interval
GROUP BY SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300,  
                                   '%Y-%m-%d %H:%i:%S' ) , 1, 19 )
ORDER BY SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300,  
                                   '%Y-%m-%d %H:%i:%S' ) , 1, 19 ) DESC

让我知道你的想法。


0
select 
CONCAT(CAST(CREATEDATE AS DATE),' ',datepart(hour,createdate),':',ROUNd(CAST((CAST((CAST(DATEPART(MINUTE,CREATEDATE) AS DECIMAL (18,4)))/5 AS INT)) AS DECIMAL (18,4))/12*60,2)) AS '5MINDATE'
,count(something)
from TABLE
group by CONCAT(CAST(CREATEDATE AS DATE),' ',datepart(hour,createdate),':',ROUNd(CAST((CAST((CAST(DATEPART(MINUTE,CREATEDATE) AS DECIMAL (18,4)))/5 AS INT)) AS DECIMAL (18,4))/12*60,2))

请为您的查询提供说明。
Daniel W.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.