tags:

views:

65

answers:

4

Here are some example numbers:

987
1001
1004
1009
1010
1016
1020
1050

For example, I would like select the top 4 numbers that close to the given number 1009 (so, the results would be 1001, 1004, 1010 and 1016), how should I write the SQL expression?

+1  A: 

Try this:

DECLARE @Target int
SET @Target = 1009

SELECT TOP 2 number from TABLE
WHERE number < @Target
ORDER BY number desc
UNION
SELECT TOP 2 number from TABLE
WHERE number > @Target
ORDER BY number asc
Abe Miessler
This has the potential to be the most sargable but you're assuming that the closest 4 numbers will be 2 bigger and 2 smaller. I think a hybrid of this and the other answers would be the best.
Martin Smith
+7  A: 

Get the distance from the given number by subtracting and using the abs function:

select top 4 Number
from NumberTable
where number <> 1009
order by abs(Number - 1009)

Edit:

As you now mention that you have a very large table, you would need a way to elliminate most of the results first. You could pick the four closest in both direction and then get the correct ones from that:

select top 4 Number
from (
  select Number
  from (
    select top 4 Number
    from NumberTable
    where number < 1009
    order by number desc
  )
  union all
  select Number
  from (
    select top 4 Number
    from NumberTable
    where number > 1009
    order by number
  )
)
order by abs(Number - 1009)

If the numbers are evenly distributed so that you are sure that you can find the numbers in a range like for example +-100 numbers, you can simply get that range first:

select top 4 Number
from (
  select Number
  from NumberTable
  where number between 1009-100 and 1009+100
)
where number <> 1009
order by abs(Number - 1009)
Guffa
That is an awesome method, I never would have thought of that. +1
Abe Miessler
Don't forget to exclude 1009 from the results too!
LukeH
@LukeH: Yes, you are right. The closest number to 1009 would of course be 1009 itself, but the example suggests that it should be excluded.
Guffa
I love popping into a random question and gaining a new method that should come in handy in the future! +1 for schoolin' me
Shaded
This is not sargable though. It will always scan all the numbers.
Martin Smith
Thank you, but my table contains 300,000+ records, so this method seems very slow.
silent
@silent: Then you would try to elliminate the majority, by for example first picking the four closest in each direction, and then get the correct ones from that.
Guffa
+2  A: 
SELECT TOP 4 number
FROM your_table
WHERE number <> @numberToMatch
ORDER BY ABS(number - @numberToMatch)
LukeH
+2  A: 

Taking bits from all other answers on this page!

Assuming an index on the number column this should perform well (at least in SQL Server)

DECLARE @Target int
SET @Target = 1009;

SELECT TOP 4 number 
FROM
(
SELECT TOP 4 number from YourTable
WHERE number < @Target
ORDER BY number desc
UNION ALL
SELECT TOP 4 number from YourTable
WHERE number > @Target
ORDER BY number asc
) d
order by abs(number - @Target)
Martin Smith