19

I am using mySQL and CodeIgniter. I have some floating point numbers in my database such as

  • 8.3456
  • 8.5555
  • 4.5556

I want to...

SELECT * FROM table WHERE value = $myvalue

but I can't use value = $myvalue in my SELECT query because $myvalue is not exactly equal to database values. I need to get the nearest value to $myvalue from database.

If $myvalue is 5 I want to select the value 4.5556.

How can I do this in mySQL?

1
  • if you have a few rows then the answers towards the top will be sufficient - however if you have millions of rows i would not recommend them as they will scan the whole table - instead see my answer at the bottom (trade-off being readability as the query is much longer - but much faster too) Commented Jun 9, 2014 at 15:12

11 Answers 11

25
select * 
from table 
order by abs(value - $myvalue)
limit 1
Sign up to request clarification or add additional context in comments.

1 Comment

Probably does a (slow) table scan.
18

Assuming that you have a 10% tolerance (+/-) you could try something like:

select * from table 
where value >= ($myvalue * .9) and value <= ($myvalue * 1.1) 
order by abs(value - $myvalue) limit 1

Slightly updated stealing from others - this should return the nearest result in the assumed tolerance range. (Also, I just noticed the where was incorrect, apologies - now it should work).

4 Comments

What if the nearest $myvalue is more than your arbitrary % away from any value?
The original requirement is not very clear. Of course if there is no "accepted range" you can say that 10000000000 is close enough to "1", assuming there is nothing better in your DB. In this case you can drop the "where" part.
Note that this will fail if $Myvalue is 0. If you really want to do this, you need to add OR (($myvalue >= (value * .9)) AND ($myvalue <= (value * 1.1)))
This will not show nearest value if he put 6 for example -> however you were on the right track with the >= and < so a +1 from me (and a +1 for not using ABS on a whole table!)-> anyone looking who sees this please see my answer bottom that will give a fast, correct result.
16
(
select   *
from     table
where    value >= $myvalue
order by value asc
limit 1
)
union
(
select   *
from     table
where    value < $myvalue
order by value desc
limit 1
)
order by abs(value - $myvalue)
limit 1

This may look counter-intuitive but the speed will be greater than the other queries shown so far.

This is due to the fact that a greater than and less than query is quicker.

Then doing an ABS on two values is nothing.

This will give you the quickest return in a single query I can think of.

Doing an ABS on a whole table will be slow as it will scan the whole table.

2 Comments

Looks like the best answer so far
This is great! For even better performance (~50%), replace UNION with UNION ALL. (I deleted my previous comment: union is the fastest possible way)
3

Take the first value from the following:

select * from table order by abs(value - $myvalue);

Comments

3

Get the largest value similar to $val:

SELECT * FROM tab WHERE val <= $val ORDER BY val DESC LIMIT 1

Get the smallest value similar to $val:

SELECT * FROM tab WHERE val >= $val ORDER BY val LIMIT 1

Get the closest value similar to $val in either direction:

SELECT * FROM tab ORDER BY abs(val - $val) LIMIT 1

Comments

2

In my case, I was using the browsers geolocations and trying to find a closest city/state based on the coordinates I had in a table.

table structure:

id    zipcode    city_state   lat    lon
1     12345      Example, GA  85.3   -83.2

Recommend testing this vigorously before using -- probably needs some tweaks, but I came up with this as a start

SELECT city_state, 
   zipcode, 
   ( Abs( lat - -33.867886 ) 
     + Abs( lon - -63.987) ) AS distance
FROM   zipcodes 
ORDER  BY distance 
LIMIT  1;  

For laravel users:

$city = Zipcodes::selectRaw
    ('city_state, zipcode,  ( ABS( lat - ? ) + ABS( lon - ?) ) AS distance', [$lat, $lon])
        ->orderBy('distance')
        ->first();

echo $city->city_state

Hope this helps someone someday.

Comments

1
SELECT * FROM table1 ORDER BY ABS(value - '$myvalue') LIMIT 1 

Comments

0
SELECT number, ABS( number - 2500 ) AS distance
FROM numbers
ORDER BY distance
LIMIT 6

Selecting closest values in MySQL

Comments

0

Try this:

SELECT *,abs((columnname -Yourvalue)) as near
  FROM table
 WHERE order by near limit 0,1

Comments

0

Unfortunately, I think your database will probably do a full table scan for solutions that involve abs, so they will be (very) slow once your table grows. A fast-running solution may be found in this earlier thread specific to PostgreSQL.

Comments

-1

Read this page http://dev.mysql.com/doc/refman/5.1/en/mathematical-functions.html#function_round

but your select would look like this

select value from table where ROUND(value) = $myvalue 

4 Comments

What if the nearest $myvalue is more than 1 away from any value?
@Bohemian - at some point your going to need a cut off point for matching the value
@Bohemian, no you don't that depends entirely on your application, and if you need a cutoff, it should always be a percentage of the original values. What if you're not dealing with 8.12, but with 15,481,254,454,875,544,545.1 instead?
The question is clear: "Pick the closest value". It doesn't say anything about how far away the value is... could be 1000 away. Your answer is, quite simply, "wrong".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.