MySql select 相对相似的日期

MySql select relative similar dates

我试图 select 来自 table 的记录同时 window,例如

record_date            |   record_data
4/20/2015 5:00:00 PM   |  23
4/20/2015 5:08:00 PM   |   3
4/20/2015 5:09:00 PM   |  98

如果我设置 2 分钟 window 将导致:

4/20/2015 5:08:00 PM   |   3
4/20/2015 5:09:00 PM   |  98

但是,如果我选择 15 分钟 window 必须得到:

4/20/2015 5:00:00 PM   |  23
4/20/2015 5:08:00 PM   |   3
4/20/2015 5:09:00 PM   |  98

如何做到这一点? BETWEEN 或 DATEDIFF 语句需要一个绝对日期来比较,在这种情况下,比较必须与其他记录值相关,而不是与外部时间相关。

Mysql 不太擅长这个(这意味着 - 没有内置的东西)。

我们需要做的是根据 record_date 顺序为每一行关联一个等级。即,第一行的排名为 1,按日期紧邻的下一行的排名为 2,依此类推。

如果我们这样做,我们就可以很容易地将一行与下一行进行比较(即将 rankrank + 1 进行比较)

这将为我们提供行对,以及按日期排列的紧接的下一行,然后我们可以过滤那些由您选择的 window 分隔的行。

为了将该结果转换为双列结果,我们需要重复查询,union 将结果放在一起,获取第一个查询中的第一个日期和数据,第二个日期和第二个查询中的数据。

union 默认为 distinct,因此我们不会得到任何重复的行。这给了我们以下查询:

select * from (
  select t1.record_date, t1.record_data from
  (select @rank := @rank + 1 as rank, records.*
    from records, (select @rank := 0) q order by record_date asc) t1
  left join
  (select @rank2 := @rank2 + 1 as rank, records.*
    from records, (select @rank2 := 0) q order by record_date asc) t2
  on t1.rank + 1 = t2.rank
  where t2.record_date < t1.record_date + interval 2 minute
union
select t2.record_date, t2.record_data from
  (select @rank := @rank + 1 as rank, records.*
    from records, (select @rank := 0) q order by record_date asc) t1
  left join
  (select @rank2 := @rank2 + 1 as rank, records.*
    from records, (select @rank2 := 0) q order by record_date asc) t2
  on t1.rank + 1 = t2.rank
  where t2.record_date < t1.record_date + interval 2 minute
) q
order by record_date asc;

demo here

或者,您可以像这样以稍微不那么夸张的方式进行操作:

select *
  from (
    select r1.record_date, r1.record_data
      from records r1
        inner join records r2
          on r2.record_date = (select min(record_date) from records where record_date > r1.record_date)
      where r2.record_date < r1.record_date + interval 2 minute
    union
    select r2.record_date, r2.record_data
      from records r1
        inner join records r2
          on r2.record_date = (select min(record_date) from records where record_date > r1.record_date)
      where r2.record_date < r1.record_date + interval 2 minute
  ) q
  order by record_date asc;

我们不考虑排名,只是通过找到它的子查询直接加入下一个顺序日期。

Updated demo here