I need to find a select statement that will return either a record that matches my input exactly, or the closest match if an exact match is not found.
Here is my select statement so far.
SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p'
ORDER BY Area DESC
What I need to do is find the closest match to the 'Area' field, so if my input is 1.125 and the database contains 2, 1.5, 1 and .5 the query will return the record containing 1.
My SQL skills are very limited so any help would be appreciated.
SQL MIN() and MAX() Functions The MIN() function returns the smallest value of the selected column. The MAX() function returns the largest value of the selected column.
ABS() function : This function in SQL Server is used to return the absolute value of a specified number. Absolute value is used for depicting the distance of a number on the number line from 0. The direction of the number from zero is not considered since the absolute value of a number is never negative.
get the difference between the area and your input, take absolute value so always positive, then order ascending and take the first one
SELECT TOP 1 * FROM [myTable] WHERE Name = 'Test' and Size = 2 and PType = 'p' ORDER BY ABS( Area - @input )
something horrible, along the lines of:
ORDER BY ABS( Area - 1.125 ) ASC LIMIT 1
Maybe?
If you have many rows that satisfy the equality predicates on Name
, Size
, and PType
columns then you may want to include range predicates on the Area
column in your query. If the Area
column is indexed this could allow efficient index-based access.
The following query (written using Oracle syntax) uses one branch of a UNION ALL
to find the record with minimal Area >=
your target, while the other branch finds the record with maximal Area <
your target. One of these two records will be the record that you are looking for. Then you can ORDER BY ABS(Area - ?input)
to pick the winner out of those two candidates. Unfortunately the query is complex due to nested SELECTS that are needed to enforce the desired ROWNUM / ORDER BY precedence.
SELECT *
FROM
(SELECT * FROM
(SELECT * FROM
(SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p' AND Area >= ?target
ORDER BY Area)
WHERE ROWNUM < 2
UNION ALL
SELECT * FROM
(SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p' AND Area < ?target
ORDER BY Area DESC)
WHERE ROWNUM < 2)
ORDER BY ABS(Area - ?target))
WHERE rownum < 2
A good index for this query would be (Name, Size, PType, Area)
, in which case the expected query execution plan would be based on two index range scans that each returned a single row.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With