0

如何从表中选择固定数量的行,其中时间戳列和返回行彼此距离相等。我需要这些点作为用于绘制时间序列的样本点。我知道解决此问题的其他技术,例如交叉过滤器等,但我现在希望能够使用服务器。

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

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 中,我看到了解决方法,就像这里的那个,但我不认为这是编写 mysql 的一种干净的方法。

关于如何解决这个问题的任何建议?

4

2 回答 2

1

You probably need a step function to map your time stamps to a finite set of "steps". This could be expressed like this in 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)

For sake of simplicity, I used here integers instead of timestamps. You will easily find in the MySQL documentation how to convert from timestamps to "unix epoch".

Once the function is defined, you just have to group by "step" in your select query, keeping only the first sample of each step:

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;

See http://sqlfiddle.com/#!2/d5ccb/3 for a live example.

于 2013-07-31T22:05:13.057 回答
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改用。

于 2013-08-01T00:39:44.410 回答