如何从表中选择固定数量的行,其中时间戳列和返回行彼此相等。我需要这些点作为样本点来绘制时间序列。我知道解决这个问题的其他技术,比如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的。
有关如何解决此问题的任何建议吗?
答案 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
。