根据MySQL中的时间戳列选择等距离的行

时间:2013-07-31 21:08:12

标签: mysql database

如何从表中选择固定数量的行,其中时间戳列和返回行彼此相等。我需要这些点作为样本点来绘制时间序列。我知道解决这个问题的其他技术,比如crossfilter等,但我现在想要能够使用服务器。

例如,下表:(为了清晰起见,简化了时间戳)

id    key    val   timestamp
1     'a'    100   1am
2     'b'    120   2am
3     'c'    130   3am
4     'd'    140   4am
5     'e'    130   5am
6     'f'    135   6am
7     'g'    136   7am
8     'h'    139   8am
9     'i'    149   9am
10    'j'    140   10am
11    'k'    140   11am
12    'l'    135   12pm

所以我希望能够运行一个返回大小为3的样本的查询,它应该返回第1,5和9行。

我不想使用id,因为我的表比这更复杂,我会将where子句应用于我的查询,因此使用ID不起作用。

从使用其他RDBS我知道RANK,但它似乎并不存在于mysql中,我看到了变通方法,就像here那样,但我不认为它是一种干净的写法MySQL的。

有关如何解决此问题的任何建议吗?

2 个答案:

答案 0 :(得分:1)

您可能需要step function将时间戳映射到一组有限的“步骤”。这可以在MySQL中表达如下:

--
-- `min_v` and `max_v` are respectively the first and last value value on the range
-- `samples` is the number of sample ("steps") expected
-- `value` is the actual value
-- 
CREATE FUNCTION step(min_v int, max_v int, samples int, value int)
RETURNS int DETERMINISTIC
RETURN min_v + (value - min_v) * (samples - 1) DIV (max_v-min_v)

为简单起见,我在这里使用了整数而不是时间戳。您可以在MySQL文档中轻松找到如何convert from timestamps to "unix epoch"

定义函数后,您只需在选择查询中按“步骤”分组,只保留每个步骤的第一个样本:

select data.k, data.value FROM tbl AS data
join (select id, MIN(ts) FROM tbl GROUP BY step(1,12,4,ts) ) as s
on s.id = data.id;

有关实例,请参阅http://sqlfiddle.com/#!2/d5ccb/3

答案 1 :(得分:1)

使用基本算术执行此操作。如果您假设(如您的示例中)时间是精确的,并且您知道您想要的第一个时间戳以及它们之间的小时数:

select t.*
from t
where mod(TIME_TO_SEC(TIMEDIFF(t.timestamp, @FirstTimeStamp)), 60*60*@HourDIff) = 0;

要计算两者之间的小时数,只需取最小和最大时间戳之差的整数部分:

select (TIME_TO_SEC(TIMEDIFF(max(t.timestamp), min(t.timestamp)) / @YOURCOUNT) as DiffSeconds;

此外,假设第一个时间戳是表格中的第一个时间戳。

现在,让我们把它们放在一起:

select t.*
from t cross join
     (select min(timestamp) as FirstTimeStamp,
             select (TIME_TO_SEC(TIMEDIFF(max(t.timestamp), min(t.timestamp)) / @YOURCOUNT) as DiffSeconds
      from t
     ) const
where mod(TIME_TO_SEC(TIMEDIFF(t.timestamp, FirstTimeStamp)), DiffSeconds) = 0;

这确实假设您的时间戳非常准确。如果这是一个问题,也许您应该使用id