2

我会尽力解释我的奇怪情况。我有一堆数据记录到十分之一秒。从时间 X 开始,几乎每秒都会发生一个事件。每一秒都被认为是一个“事件窗口”。记录的时间是从 X 开始的经过时间。使用第一条记录作为“种子”,我只需要从 X.X+1、X+2、X+3 返回每隔一秒窗口记录的第一条记录, X+4 等。

targets
--------------------------
| id  | time  | name     |
|-----|------ |-----------
| 1   |  1.0  | target01 |
| 2   |  1.1  | target01 |
| 3   |  1.2  | target01 |
| 4   |  1.3  | target01 |
| 5   |  1.4  | target01 |
| 6   |  1.5  | target01 |
| 7   |  1.6  | target01 |
| 8   |  1.7  | target01 |
| 9   |  1.8  | target01 |
| 10  |  1.9  | target01 |
| 11  |  2.0  | target01 |
| 12  |  2.1  | target01 |
| 13  |  2.2  | target01 |

...

| 50  |  4.9  | target01 |
| 51  |  5.3  | target01 |
| 52  |  5.4  | target01 |
| 53  |  5.5  | target01 |
| 54  |  5.6  | target01 |
| 55  |  5.7  | target01 |
| 56  |  5.8  | target01 |
| 57  |  5.9  | target01 |
| 58  |  6.0  | target01 |
| 59  |  6.1  | target01 |
| 60  |  6.2  | target01 |
| 61  |  6.3  | target01 |
| 62  |  6.4  | target01 |
--------------------------

我将如何得到这个作为回报:

--------------------------
| id  | time  | name     |
|-----|------ |-----------
| 1   |  1.0  | target01 |
| 11  |  2.0  | target01 |
| 21  |  3.0  | target01 |
| 31  |  4.0  | target01 |
| 51  |  5.3  | target01 |
| 58  |  6.0  | target01 |
--------------------------

请注意,记录 51 位于 5.3 秒处。它是落在该四秒窗口 (X+4) 内的第一条记录。

糟糕的数据库规划,但我被困在继承混乱中。想法?

4

5 回答 5

0

你需要像Rank()这样的分析函数,但我很确定 MySQL 不会这样做。

select Id, Time, Name
from
(
    SELECT Id, Time, Name, 
           Rank() OVER(PARTITION BY Floor(time) ORDER BY time Asc) AS Rank
    FROM  @aTable
) SubSelect
where Rank = 1

您可以在 data.stackexchange.com 上查看示例。

于 2012-12-19T20:26:05.313 回答
0

鉴于该time列是数字,并且 没有“重复”值time,那么这样的事情将起作用:

SELECT d.id
     , d.time
     , d.name
  FROM mytable d
  JOIN ( SELECT MIN(t.time) AS `time`
           FROM mytable t
          GROUP BY FLOOR(t.time)
       ) m
    ON m.time = d.time
 ORDER BY d.time

(对于该查询,如果在一秒钟内最低值存在“重复”值time,则将返回这两行。这可以通过GROUP BY最外层查询上的简单查询来解决,只要它们中的哪一个是任意的返回行。

(该查询将返回您指定的结果集。不清楚您是否也想要这个“按名称”,所以我省略了。


请注意,还有一些其他方法,其中一些在大型集合上表现得更好。


另一种(特定于 MySQL 的)方法使用用户变量:

SELECT t.id
     , t.time
     , t.name
  FROM ( SELECT s.id
              , s.time
              , s.name
              , @prev AS `prev_sec`
              , @prev := FLOOR(s.time) AS `this_sec`
           FROM targets s
           JOIN (SELECT @prev := '') p
          ORDER BY s.time
       ) t
 WHERE prev_sec <> this_sec

(谨慎使用 SQL 语句中的用户变量。可以在行为可预测的情况下构造语句,但有时行为是“出乎意料的”,如果不了解执行计划、步骤运行的顺序和变量将在哪一步被设置。


另一种(通常性能较慢)的替代方法是使用NOT EXISTS谓词来排除在同一秒内有“较早”时间的行。

有时,如果查询正在提取一小组时间值(即,严格的行范围,例如从一年的数据中提取一小时的行)并且如果适当索引可用,尤其是覆盖索引,或至少一个以time作为前导列的索引。

SELECT t.id
     , t.time
     , t.name
  FROM targets t
 WHERE NOT EXISTS
       ( SELECT 1
           FROM targets e
          WHERE e.time >= FLOOR(t.time)
            AND e.time < t.time
       )
 ORDER
    BY t.time

time(此查询与答案中给出的第一个查询一样,如果这些time值在任何一秒内都是最低的,也将返回两行或多行具有重复值的行。)

于 2012-12-19T19:03:00.843 回答
0

做这个:

select * from (
    select * from targets
    order by time) x
group by floor(time)

看到这个在 SQLFiddle 上工作

于 2012-12-19T18:58:04.880 回答
0

您可能需要使用FLOORandCOALESCE函数

SELECT FLOOR(time) AS whole_second, COALESECE(id), COALESCE(time), COALESCE(name)
FROM table
GROUP BY whole_second
ORDER BY whole_second ASC
于 2012-12-19T18:58:52.823 回答
0

尝试这个:

select *
from targets t
where time % 1 = (
  select min(time % 1) 
  from targets 
  where floor(time) = floor(t.time))

SQLFiddle

于 2012-12-19T20:09:46.073 回答