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

sky*_*sky 81 mysql sql group-by

我想要做的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
Run Code Online (Sandbox Code Playgroud)

这是我目前的输出声明.

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
Run Code Online (Sandbox Code Playgroud)

如何将它们分组为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 
Run Code Online (Sandbox Code Playgroud)

boe*_*cko 132

这适用于每个间隔.

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 
WHERE …
GROUP BY 
round(extract('epoch' from timestamp) / 300), name
Run Code Online (Sandbox Code Playgroud)


MySQL的

SELECT
    timestamp,  -- not sure about that
    name,
    count(b.name)
FROM time a, id 
WHERE …
GROUP BY 
UNIX_TIMESTAMP(timestamp) DIV 300, name
Run Code Online (Sandbox Code Playgroud)

  • 确定..而不是提取.. GROUP BY round(UNIX_TIMESTAMP(timestamp)/ 300)应该可以解决问题 (2认同)
  • @matiL的注释在mySql上是正确的你应该使用DIV而不是圆(/)否则间隔之间的边界是错误的 (2认同)

pHi*_*HiL 28

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


Sco*_*ger 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
Run Code Online (Sandbox Code Playgroud)

你可以提供各种分辨率,如'分钟','小时','天'等...到date_trunc.

  • 你在哪里设置5分钟的"5"? (29认同)
  • @tmarthal - 它不应该被投票.最初的问题是mysql. (7认同)
  • 该查询似乎没有执行所要求的操作,问题是“每5分钟”而不是现在的5分钟。答案适合被否决 (2认同)

Nes*_*nez 26

我遇到了同样的问题.

我发现,很容易按任何分钟间隔只是除以划时代通过在几秒钟量分钟,然后任一舍入或使用地板获取余数的乘坐.因此,如果您想在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
Run Code Online (Sandbox Code Playgroud)

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 

SELECT generate_series(MIN(date_trunc('hour',timestamp_column)),
max(date_trunc('minute',timestamp_column)),'5m') as interval_alias FROM 
TABLE_NAME
Run Code Online (Sandbox Code Playgroud)

on series.minute = cnt.interval_alias

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
Run Code Online (Sandbox Code Playgroud)

最终结果将包括所有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',但它可以是我们想要的任何间隔.

  • 如果它是 MySQL,它会是。似乎 generate_series 是一个 PostgreSQL 函数。太糟糕了。 (3认同)

WAS*_*D42 10

查询将类似于:

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
Run Code Online (Sandbox Code Playgroud)


Bil*_*ber 5

您可能必须将时间戳分解为 ymd:HM 并使用 DIV 5 将分钟分为 5 分钟的 bin - 类似

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
Run Code Online (Sandbox Code Playgroud)

...然后对客户端代码中的输出进行模糊处理,使其按照您喜欢的方式显示。或者,如果您愿意,您可以使用 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'))
Run Code Online (Sandbox Code Playgroud)

...然后对此进行分组


小智 5

不确定你是否还需要它。

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

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 |