从数据库中获取最接近所选日期的唯一数据

时间:2018-09-02 16:44:06

标签: mysql sql

我想获取过去或将来最接近特定日期的数据,无论哪个更接近该日期。但我还需要distinct之前type。例如:

id |type |data | date                
 1 |0    |1904 |2018-08-19 00:14:32
 2 |0    |1904 |2018-08-19 00:24:47
 3 |0    |1904 |2018-08-19 05:02:30
 4 |0    |1904 |2018-08-22 00:05:58
 5 |0    |1904 |2018-08-22 00:08:34
 6 |4    |1903 |2018-08-19 00:14:31
 7 |6    |1926 |2018-08-19 00:14:32
 8 |6    |1926 |2018-08-19 04:44:10
 9 |6    |1926 |2018-08-19 04:52:58
10 |6    |1926 |2018-08-19 04:59:23
11 |6    |1926 |2018-08-22 00:05:58
12 |6    |1926 |2018-08-22 00:07:52
13 |6    |1926 |2018-08-22 00:08:34
14 |7    |1564 |2018-08-19 00:14:32
15 |8    |1900 |2018-08-19 00:14:32 

如果我指定日期时间:2018-08-19 00:00:00。我应该得到以下结果:

id | type
 1 | 0    
 6 | 4
 7 | 6
14 | 7
15 | 8

或者,如果我指定日期时间:2018-09-03 00:00:00。我希望:

id | type
 5 | 0    
 6 | 4
13 | 6
14 | 7
15 | 8

或者最后:2018-08-22 00:05:58

id | type
 4 | 0    
 6 | 4
11 | 6
14 | 7
15 | 8

我尝试了一些没有实际意义的查询...

SELECT *
FROM history 
WHERE (ABS(TIMESTAMPDIFF(DAY, date, "2018-08-19 00:08:34")) < 4) AND user_id = 1299
GROUP BY type
ORDER BY date

无论如何,仅通过MySQL查询就能做到吗?我是否需要使用一些应用程序逻辑来实现这一目标?我该如何查询?

SQL fiddle

4 个答案:

答案 0 :(得分:2)

这采用标准查询模式来为每种类型查找具有极值的行。在这种情况下, extreme 表示最接近目标值。

首先,您需要一个聚合子查询来获取极值:每种类型的行与目标日期之间的最小增量时间。 (http://sqlfiddle.com/#!9/b51a7a/26/1

      SET @target := '2018-08-20 00:00:00';
      SELECT type, MIN(ABS(TIMESTAMPDIFF(MINUTE, date, @target))) delta
        FROM history
       GROUP BY type

然后,使用ON子句将其与原始表连接,以同时匹配类型和增量时间。全部放在一起(http://sqlfiddle.com/#!9/b51a7a/27/1

SET @target := '2018-08-20 00:00:00';
SELECT history.*
  FROM history
  JOIN (
          SELECT type, MIN(ABS(TIMESTAMPDIFF(MINUTE, date, @target))) delta
            FROM history
           GROUP BY type
      ) delta ON history.type=delta.type 
              AND ABS(TIMESTAMPDIFF(MINUTE, date, @target)) = delta

修改,可以轻松获取日期中最接近的将来或过去的日期。子查询(最近的查询)是

         SELECT type, MAX(date) date
           FROM history
         WHERE date <= @target
         GROUP BY date

则整个查询为

  SELECT history.*
    FROM history
    JOIN (
             SELECT type, MAX(date) date
               FROM history
             WHERE date <= @target
             GROUP BY date
         ) m ON history.type = m.type AND history.date = m.date 

答案 1 :(得分:0)

您可以在子查询中使用内部联接来实现最小差异

select 
    h.id, h.type 
from 
    history  
inner join  
    (select
         type, min(TIMESTAMPDIFF(SECOND, date, '2012-06-06 15:20:18')) min_diff 
     from  
         history
     where
         (abs(TIMESTAMPDIFF(DAY, date, "2018-08-19 00:08:34")) < 4) 
         and user_id = 1299
     group by  
         type) t on t.type = h.type 
                 and TIMESTAMPDIFF(SECOND, h.date, '2012-06-06 15:20:18') = t.min_diff

答案 2 :(得分:0)

您可以通过row_number()模仿其他RDBMS排序中的abs(timestampdiff(second, date, @dt))功能:

select @rn := 0, @dt := cast('2018-08-19 04:52:00' as datetime);
select id, type from (
    select id,
           type,
           data,
           date,
           @rn := @rn + 1 rn
    from history
    order by abs(timestampdiff(second, date, @dt))
) a where rn = 1;

DEMO

答案 3 :(得分:0)

这应该可以解决问题。

create table test2 as
select c.id,c.type from(
select a.*,b.min
from test as a
left join
(select id, min(abs(date-"2018-09-01 00:00:00"dt)) as min from test
group by type ) as b
on a.id = b.id
) as c
where min = abs(date-"2018-09-01 00:00:00"dt)
order by id;

我们将id上的join回到最小原始日期差异,然后选择所需的记录。