2015-02-17 5 views
0

У меня есть таблица, полная почтовых индексов. Например:MySQL Выберите N самых близких почтовых кодов для каждой строки

------------------------------ 
| zip | latitude | longitude | 
------------------------------ 
|00001| 35.34543 | -76.34234 | 
|00002| 43.23423 | -80.32423 | 
... 
|00008| 24.34543 | -20.53454 | 
------------------------------ 

Для каждой строки я хочу выбрать n ближайших почтовых индексов. Однако я могу только представить, как выбрать самый близкий почтовый индекс. Как я могу адаптировать это для всех почтовых индексов:

SELECT 
    zip, (
    3959 * acos (
     cos (radians(78.3232)) 
     * cos(radians(latitude)) 
     * cos(radians(longitude) - radians(65.3234)) 
     + sin (radians(78.3232)) 
     * sin(radians(latitude)) 
    ) 
) AS distance 
FROM zipcodes 
ORDER BY distance 
LIMIT 0 , 20; 

Это выбрать 20 закрывает почтовые индексы, но мне нужно было бы применить это к каждой строке. Как я могу сделать это для всей таблицы сразу?

+0

Правильно ли это SQL? есть ли функция, называемая «расстояние»? у вас есть zip, distance (formula) как расстояние. Может быть, вы просто хотите формулу как расстояние? – koriander

+0

Кстати, это можно сделать, но это будет тяжело в вычислении. возможно, взгляните на этот пост сначала http://stackoverflow.com/questions/1006654/fastest-way-to-find-distance-between-two-lat-long-points – koriander

+0

проверьте вторую формулу на [philcolbourn answer] (http://stackoverflow.com/questions/481144/equation-for-testing-if-a-point-is-inside-a-circle) Я думаю, что он больше подходит для вас. – josegomezr

ответ

0

После прочтения this, я думаю, что вы можете использовать Haversine формулу для вычисления расстояния между двумя точками, с учетом широты и долготы каждого из них:

Вот пример:

select zc.* 
    -- First, convert the latitude and longitude to radians: 
    , @lat1 := radians(@latitude) as lat1_rad 
    , @lon1 := radians(@longitude) as lon1_rad 
    , @lat2 := radians(zc.latitude) as lat2_rad 
    , @lon2 := radians(zc.longitude) as lon2_rad 
    -- Calculate the differences in latitude and longitude: 
    , @delta_lat := @lat2 - @lat1 as delta_lat 
    , @delta_lon := @lon2 - @lon1 as delta_lon 
    -- The Haversine Formula: 
    , @a := pow(sin(@delta_lat/2), 2) + cos(@lat2) * cos(@lat1) * pow(sin(@delta_lon/2), 2) as a 
    , @c := 2 * atan2(sqrt(@a), sqrt(1 - @a)) as c 
    , @d := @R * @c as d -- Distance (Km) 
from 
    (select @R := 6371 -- The radius of the earth (Km) 
      , @latitude := 65.3234 -- Latitude of the initial point 
      , @longitude := -78.3232 -- Longitude of the initial point 
    ) as init, 
    zip_codes as zc 
-- Add any WHERE conditions and/or ORDER 
; 

Если вы хотел бы поместить это в функцию:

delimiter $$ 
create function haversine_distance(latitude1 double, longitude1 double 
           , latitude2 double, longitude2 double) 
returns double 
-- Input: Latitude and longitude of the points you want to calculate, 
      given in degrees 
begin 
    declare lat1, lon1, lat2, lon2 double; 
    declare delta_lat, delta_lon double; 
    declare a, c, d double; 
    declare R double default 6371; -- The radius of the Earth 
    -- Convert the inputs to radians 
    set lat1 = radians(latitude1); 
    set lon1 = radians(longitude1); 
    set lat2 = radians(latitude2); 
    set lon2 = radians(longitude2); 
    -- Calculate the differences between latitudes and longitudes 
    set delta_lat = lat2 - lat1; 
    set delta_lon = lon2 - lon1; 
    -- The Haversine formula 
    set a = pow(sin(@delta_lat/2), 2) + 
      cos(lat2) * cos(lat1) * pow(sin(delta_lon/2), 2); 
    set c = 2 * atan2(sqrt(a), sqrt(1 - 1); 
    set d = R * c; 
    return d; 
end $$ 
delimiter ; 

И, наконец, вы можете использовать эту функцию для расчета расстояний между двумя точками s и фильтровать ближайший n. Я буду использовать пользовательские переменные для определения широты и долготы исходной точки:

set @latitude1 = 65.3234, @longitude1 = -78.3232; 
set @n = 5; -- The number of nearest points 
select zc.* 
    , haversine_distance(@latitude1, @longitude1, 
          zc.latitude, zc.longitude) as distance_km 
from zip_codes as zc 
order by distance_km 
limit @n; 
Смежные вопросы