14

I am trying to find a datetime value in a mysql database that is the closest match to a datetime that i specify, i am having some trouble.

The following pseudo code is what i want to achieve:

SELECT one FROM table WHERE datetimefield is closest to "2014-12-10 09:45:00" LIMIT 1
Dharman
  • 30,962
  • 25
  • 85
  • 135
Jack Hayfield
  • 207
  • 1
  • 3
  • 9

3 Answers3

35

The key idea is to use order by and limit:

If you want the closest one before:

SELECT one
FROM table
WHERE datetimefield <= '2014-12-10 09:45:00'
ORDER BY datetimefield DESC
LIMIT 1;

If you want the closest, in either direction, then use TIMESTAMPDIFF():

ORDER BY abs(TIMESTAMPDIFF(second, datetimefield, '2014-12-10 09:45:00'))
LIMIT 1
Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
  • 1
    Thanks for this, i have updated the OP with an updated query that works but is very performance intensive if you would be so kind as to shed some light on it, cheers – Jack Hayfield Dec 10 '14 at 15:07
  • 1
    @JackHayfield . . . That edited portion should be another question, not an addendum on this question. – Gordon Linoff Dec 11 '14 at 00:17
5

Using abs() prevents using a datetimefield index. I propose to have one select for the closest before and one select for the closest after, both using the index, and picking the closest of them afterwards:

create table `table` (datetimefield datetime key, one varchar(99));
insert into `table` values
  ('2014-06-01', 'a'), ('2014-12-01', 'b'),
  ('2015-01-01', 'c'), ('2015-02-01', 'd');

set @d = '2014-12-10 09:45:00';

select * from
(
  ( select *, TIMESTAMPDIFF(SECOND, @d, datetimefield) as diff
    from `table` where datetimefield >= @d
    order by datetimefield asc  limit 1
  )
  union
  ( select *, TIMESTAMPDIFF(SECOND, datetimefield, @d) as diff
    from `table` where datetimefield < @d
    order by datetimefield desc limit 1
  )
) x
order by diff
limit 1;

http://sqlfiddle.com/#!2/bddb4/1

Julian Ladisch
  • 1,367
  • 9
  • 10
  • 3
    More complicated isn't necessarily a bad thing if it is better performance... which is the point of his post. – thaspius Dec 14 '15 at 18:10
4

Use ABS()

SELECT one FROM table 
ORDER BY ABS(`datetimefield` - '2014-12-10 09:45:00') LIMIT 1

This will return the row with lowest difference, that is closest.

Pupil
  • 23,834
  • 6
  • 44
  • 66