MySQL查询中基于日期的第n条记录

时间:2011-06-28 19:56:58

标签: php mysql datetime range


我正在创建一个基于jquery的Web图表来显示天气数据。数据通过Ajax加载 - > PHP - > MySQL的。 MySQL数据库包含过去10年每分钟的各种参数记录......(所以记录的数量很大)。我希望用户能够为自定义日期范围生成图表,但是限制我为日期范围提取的数据的数量超过几天。即,如果他们查询一周的数据,我的PHP代码应该每小时只返回1个数据值。
我不想做任何平均,或者那种服务器端处理 - 我只想从mysql中检索每个第n条记录 - 这样我就可以获得可管理的数据量。

我的问题是,我的数据库没有记录号字段,我无法修改数据库的格式。有没有办法可以根据实际日期值来做到这一点?就像说转换为unix时间戳,然后只选择记录,如果日期可以被某个数字整除? (我会根据时间范围的长度来计算数字,以拉出固定数量的点数)

有关良好方法的任何想法吗?如果有一个解决方案可以让我直接选择均匀的时间间隔,那将是理想的。 (即每5分钟,10分钟,1小时,5小时等)

编辑:该字段是MySQL dateTime格式!!谢谢你要求澄清!

3 个答案:

答案 0 :(得分:1)

您可以在SQL WHERE子句中使用MOD()UNIX_TIMESTAMP()函数

SELECT * FROM WEATHER WHERE MOD(UNIX_TIMESTAMP(Time), Divisor) = 0

只会让你获得可以被Divisor整除的时间记录。除数将是你想要获取数据的任何时间增量(每5分钟300个,每1.5个小时5400个等)。

由于UNIX Time使用32位int,因此MySQL中的标准INT数据类型就可以了。

答案 1 :(得分:0)

您可以将DATETIME转换为UNIX时间戳,除以所需时间间隔内的秒数(以下示例中为10分钟),然后使用GROUP BY将每个不同值减少为一行。

SELECT FLOOR(UNIX_TIMESTAMP(datetime_col)/600) AS ts, * FROM WEATHER 
WHERE datetime_col BETWEEN ? AND ?
GROUP BY ts

这不会很快,因为它必须为每一行计算ts,然后将其作为未编制索引的列进行分组。

这也取决于MySQL的非标准行为,它允许不明确的GROUP BY查询。也就是说,它返回组中的一些任意行,由存储引擎确定。在实践中,它是物理存储的第一行,但这可能会因为存储引擎,覆盖索引等而变得混乱。

替代方法:您可以使用用户变量来计算行数,并在间隔更改时仅返回第一行。

SET @interval := 0;
SET @row := 0;
SELECT t.* FROM (
SELECT (@i:=FLOOR(UNIX_TIMESTAMP(datetime_col)/600)),
  IF(@interval<>@i),@row:=0,@row:=@row+1) AS row, @interval:=@i, *
FROM WEATHER
WHERE datetime_col BETWEEN ? AND ?
) AS t
WHERE t.row = 0;

答案 2 :(得分:0)

  

比如说要转换为unix时间戳,那么只有当日期可被某个数字整除时才选择记录?

这个问题,大多数方法是你仍然必须读取所有连续点(除非你有包含时间戳的各种表示的索引列),所以你可能会减小结果集的大小但不是提取它所需的工作量。

您可以创建一个新表(不必在同一个数据库/服务器中 - 您仍然可以使用联合引擎连接到原始数据)?这样你就可以在河内序列的塔中设置一个具有不同粒度的时间戳表,例如

date time       level
-------------   -----
201101010000    0
201101010010    6
201101010020    6
201101010030    5
201101010040    6
201101010050    6
201101010100    4
201101010110    6
201101010120    6
201101010130    5
...
201101020000    3
...

这样你就可以在适当的粒度级别从这个故事中选择并加入到底层的原始数据。

上面的内容可以作为汇总数据的函数 - 但是无法从中查找,您仍然需要读取src数据中的所有插入行。

  

如果有一个解决方案可以让我直接选择均匀的时间间隔

像......那样的东西。

 SELECT DATE_FORMAT(yourdate, SUBSTR('%Y%m%d%H%i%s',0,2*@level)) as t,
 AVG(value)
 FROM yourtable
 WHERE yourdate BETWEEN @datestart AND @dateend
 GROUP BY DATE_FORMAT(yourdate, SUBSTR('%Y%m%d%H%i%s',0,2*@level))
 ORDER BY 1;

(如上所述 - 没有第二个表加入或使用索引仅选择需要的数据样本的另一种方法,使用聚合fn没有性能损失。)