Masz tam całkiem dobre odniesienie do wyszukiwania odległości mySQL.
Zapomnij o rzeczach związanych z Oracle Spatial. Za dużo kodu, za dużo złożoności, za mało wartości dodanej.
Oto zapytanie, które załatwi sprawę. Wykorzystuje odległości w milach ustawowych. EDYTUJ To naprawia błąd wspomniany przez mdarwina, kosztem sprawdzenia dzielenia, jeśli spróbujesz użyć go dla lokalizacji na biegunie północnym lub południowym.
SELECT id, city, LATITUDE, LONGITUDE, distance
FROM
(
SELECT id,
city,
LATITUDE, LONGITUDE,
(3959 * ACOS(COS(RADIANS(LATITUDE))
* COS(RADIANS(mylat))
* COS(RADIANS(LONGITUDE) - RADIANS(mylng))
+ SIN(RADIANS(LATITUDE))
* SIN(RADIANS(mylat))
))
AS distance,
b.mydst
FROM Cities
JOIN (
SELECT :LAT AS mylat,
:LONG AS mylng,
:RADIUS_LIMIT AS mydst
FROM DUAL
)b ON (1 = 1)
WHERE LATITUDE >= mylat -(mydst/69)
AND LATITUDE <= mylat +(mydst/69)
AND LONGITUDE >= mylng -(mydst/(69 * COS(RADIANS(mylat))))
AND LONGITUDE <= mylng +(mydst/(69 * COS(RADIANS(mylat))))
)a
WHERE distance <= mydst
ORDER BY distance
Jeśli pracujesz w kilometrach, zmień mydst/69 na mydst/111.045 i zmień 3959 na 6371.4. (1/69 zamienia mile na stopnie; 3959 to wartość promienia planety).
Teraz prawdopodobnie pokusisz się o użycie tego dużego zapytania jako „magicznej czarnej skrzynki”. Nie rób tego! Nie jest to trudne do zrozumienia, a jeśli to zrozumiesz, będziesz w stanie wykonywać lepszą pracę. Oto, co się dzieje.
Ta klauzula jest sednem tego, co sprawia, że zapytanie jest szybkie. Przeszukuje tabelę Miasta w poszukiwaniu pobliskich miast do określonego punktu.
WHERE LATITUDE >= mylat -(mydst/69)
AND LATITUDE <= mylat +(mydst/69)
AND LONGITUDE >= mylng -(mydst/(69 * COS(RADIANS(mylat))))
AND LONGITUDE <= mylng +(mydst/(69 * COS(RADIANS(mylat))))
Aby to zadziałało, zdecydowanie potrzebujesz indeksu w kolumnie LATITUDE. Pomocny będzie również indeks w kolumnie LONGITUDE. Wykonuje przybliżone wyszukiwanie, szukając wierszy, które znajdują się w quasi-prostokątnej łacie na powierzchni ziemi w pobliżu twojego punktu. Wybiera zbyt wiele miast, ale niezbyt wiele.
Ta klauzula pozwala wyeliminować dodatkowe miasta z zestawu wyników:
WHERE distance <= mydst
Ta klauzula to formuła haversine, która oblicza odległość wielkiego koła między każdym miastem a twoim punktem.
(3959 * ACOS(COS(RADIANS(LATITUDE))
* COS(RADIANS(mylat))
* COS(RADIANS(LONGITUDE) - RADIANS(mylng))
+ SIN(RADIANS(LATITUDE))
* SIN(RADIANS(mylat))
Ta klauzula umożliwia jednokrotne wprowadzenie punktu i limitu promienia jako zmiennych powiązanych z zapytaniem. Jest to pomocne, ponieważ różne formuły wielokrotnie wykorzystują te zmienne.
SELECT :LAT AS mylat,
:LONG AS mylng,
:RADIUS_LIMIT AS mydst
FROM DUAL
Reszta zapytania po prostu porządkuje rzeczy, dzięki czemu można wybierać i porządkować według odległości.
Oto pełniejsze wyjaśnienie:http://www.plumislandmedia.net /mysql/haversine-mysql-nearest-loc/