Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select closest numerical value with MySQL query

Tags:

sql

mysql

This is probably easier than I am making it, but basically what I need to do is select the row that has the closest number in a column as a specified value. For example:

List of values in database for 3 rows in a specified column: 10, 15, 16

If I specify that I want the row that is closest to 14, it would pick the row with 15.

Also, if there are 2+ rows that are the same distance, pick one of them randomly.

like image 465
James Simpson Avatar asked Oct 28 '09 01:10

James Simpson


People also ask

How do I select only the value of an integer in MySQL?

Syntax to check if the value is an integer. select yourColumnName from yourTableName where yourColumnName REGEXP '^-?[0-9]+$'; The query wherein we have used regular expression. This will output only the integer value.

How do I select a specific value from a table in MySQL?

MySQL SELECT statement is used to retrieve rows from one or more tables. The statement can also include UNION statements and subqueries. SELECT statement is used to fetch rows or records from one or more tables.

How do I select specific in MySQL?

If you want to select only specific columns, replace the * with the names of the columns, separated by commas. The following statement selects just the name_id, firstname and lastname fields from the master_name table.


3 Answers

One option would be something along the lines of:

select   the_value,
         abs(the_value - 14) as distance_from_test
from     the_table
order by distance_from_test
limit 1

To select a random record, you can add , rand() to the order by clause. The disadvantage of this method is that you don't get any benefit from indices because you have to sort on the derived value distance_from_test.

If you have an index on the_value and you relax your requirement for the result to be random in the case of ties, you can perform a pair of limited range queries to select the first value immediately above the test value and the first value immediately below the test value and pick whichever is closest to the test value:

(
select   the_value
from     the_table
where    the_value >= 14
order by the_value asc
limit 1
)
union
(
select   the_value
from     the_table
where    the_value < 14
order by the_value desc
limit 1
)
order by abs(the_value - 14)
limit 1
like image 64
James McNellis Avatar answered Nov 15 '22 19:11

James McNellis


In order to use an index, you could select the minimum value above the target, and the maximum value below. Then you only have two values to check.

like image 23
recursive Avatar answered Nov 15 '22 19:11

recursive


How would you handle tie breakers? Because this will only take the first:

  SELECT t.col
    FROM TABLE t
ORDER BY ABS(t.col - @val)
   LIMIT 1

Index safe alternative:

  SELECT xt.col
    FROM (SELECT t.col,
                 ABS(t.col - @val) 'diff'
            FROM TABLE t) xt
ORDER BY xt.diff
   LIMIT 1
like image 43
OMG Ponies Avatar answered Nov 15 '22 20:11

OMG Ponies