2011-09-21 2 views
1

위도, 경도 및 반경 매개 변수를 기반으로 가장 가까운 도시를 계산하는이 함수가 있습니다.지리적 위치 거리 도시 테이블의 SQL

> +------------+-------------+------+-----+---------+----------------+ | 
> Field  | Type  | Null | Key | Default | Extra   | 
> +------------+-------------+------+-----+---------+----------------+ | 
> id   | int(11)  | NO | PRI | NULL | auto_increment | | 
> country_id | smallint(6) | NO |  | NULL |    | | 
> region_id | smallint(6) | NO |  | NULL |    | | 
> city  | varchar(45) | NO |  | NULL |    | | 
> latitude | float  | NO |  | NULL |    | | 
> longitude | float  | NO |  | NULL |    | | 
> timezone | varchar(10) | NO |  | NULL |    | | 
> dma_id  | smallint(6) | YES |  | NULL |    | | 
> code  | varchar(4) | YES |  | NULL |    | 
> +------------+-------------+------+-----+---------+----------------+ 

그것은 매우 잘 작동 :

DELIMITER $$ 
DROP PROCEDURE IF EXISTS `world_db`.`geolocate_close_cities`$$ 
CREATE PROCEDURE `geolocate_close_cities`(IN p_latitude DECIMAL(8,2), p_longitude DECIMAL(8,2), IN p_radius INTEGER(5)) 
BEGIN 
     SELECT id, country_id, longitude, latitude, city, 
     truncate((degrees(acos(sin(radians(latitude)) 
     * sin(radians(p_latitude)) 
     + cos(radians(latitude)) 
     * cos(radians(p_latitude)) 
     * cos(radians(p_longitude - longitude)))) 
     * 69.09*1.6),1) as distance 
     FROM cities 
     HAVING distance < p_radius 
     ORDER BY distance desc; 
    END$$ 

DELIMITER ; 

여기 내 도시 테이블의 구조입니다. 내가 할 (pseudcode를) LKE 것 무엇

은 같은 것입니다 :

SELECT * FROM cities WHERE DISTANCE(SELECT id FROM cities WHERE id={cityId}, {km)) 

그것은 나에게 가장 가까운 도시를 돌아갑니다.

어떻게 할 수 있습니까?

지금은 함수를 호출 한 다음 ID를 배열로 반복 한 다음 도시 테이블에서 WHEREIN을 수행합니다. 이는 분명히 효율적이지 않습니다.

도움이 필요합니다. 감사.

답변

1

도시와 현지 위치 간의 최대 거리를 제한 할 수있는 경우 위도 1 분 (남북)은 1 해리입니다.

위도 테이블에 색인을 붙이십시오.

질문에 표시된 haversine 수식에서 haversine (lat1, lat2, long1, long2, unit) 함수를 저장하십시오. 아래 참조

다음 mylatitude, mylongitude 및 mykm 주어진이 작업을 수행하십시오.

SELECT * 
    from cities a 
where :mylatitude >= a.latitude - :mykm/111.12 
    and :mylatitude <= a.latitude + :mykm/111.12 
    and haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM') <= :mykm 
order by haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM') 

이렇게하면 위도 경계 상자를 사용하여 지나치게 멀리 떨어진 도시를 배제 할 수 있습니다. DBMS는 위도 색인에서 색인 범위 검사를 사용하여 고려할 가치가있는 도시 테이블의 행을 신속하게 선택합니다. 그러면 모든 행과 사인 수학이있는 하바 네틴 함수가 실행됩니다.

경도의 지상 거리가 위도와 다르기 때문에 위도를 제안합니다.

참고로 이것은주의해야합니다. 스토어 파인더는 괜찮지 만 토목 기술자 인 경우에는 사용하지 마십시오. 지구는 타원형이며 원형이라고 가정합니다.

합니다 (111.12 매직 넘버 대해 죄송합니다. 즉 위도의 정도 km의 수는 예순 해리에,입니다.)


실행 가능한 거리 함수 여기를 참조하십시오.

Why does this MySQL stored function give different results than to doing the calculation in the query?

+0

안녕하세요 @ 올리 존스. 신속한 응답에 감사드립니다. 솔직히 말해서, 나는 당신의 SQL이하는 것과 일치하도록 내 함수를 변경하는 방법을 완전히 이해한다는 것을 너무 확신하지 못한다. 감사! :-) – Flukey

+0

내가 하버 사인 공식을 createde 것은, 여기 내 쿼리 : cities_temp에서 'SELECT * 곳 52.205> = a.latitude - 100/111.12 과 52.205 <= a.latitude + 100/111.12 및 하버 사인 (52.205, 위도가 52.205이고 경도가 0.144 인 경우 (52.205, a.latitude, 0.144, a.longitude, 'KM') 위도 (0.144, a.longitude, 'KM') <= 100 영국 케임브리지) – Flukey

0

나는 this other question을 살펴볼 것입니다. 도움이 될 것입니다.

+0

어떻게 작동합니까? :-) – Flukey

+0

위도, 경도 및 거리는 전달되는 params입니다. 정확하지는 않지만 적절한 추정이어야합니다. 얼마나 정확해야합니까? –

+0

정확한 '시간 결정적'이 아닙니다. 사용자가 '내 영역의 사용자'를 클릭합니다.그들은 라디오를 선택할 수 있고 그것들에 가까운 도시들을 걸러 낼 것입니다. 참고 : 현재 상당히 정확합니다. 물론 일부는 몇 킬로미터 밖에 나가지 않지만 큰 문제는 아닙니다. 실제로 더 정확할수록 더 좋습니다! 그러나 나는 또한 효율성을 원한다. – Flukey

관련 문제