Det finns inga geospatiala förlängningsfunktioner i MySQL som stöder latitud/longitud avståndsberäkningar. Det finns från och med MySQL 5.7
.
Du ber om närhetscirklar på jordens yta. Du nämner i din fråga att du har lat/lång-värden för varje rad i dina flags
tabell, och även universell tvärgående Mercator
(UTM) projicerade värden i en av flera olika UTM-zoner
. Om jag minns mina kartor från UK Ordnance Survey korrekt, är UTM användbart för att hitta föremål på dessa kartor.
Det är enkelt att beräkna avståndet mellan två punkter i samma zon i UTM:det kartesiska avståndet gör susen. Men när punkter är i olika zoner fungerar inte den beräkningen.
Följaktligen, för applikationen som beskrivs i din fråga, är det nödvändigt att använda Great Circle Distance , som beräknas med hjälp av haversin eller annan lämplig formel.
MySQL, utökat med geospatiala förlängningar, stöder ett sätt att representera olika plana former (punkter, polylinjer, polygoner och så vidare) som geometriska primitiver. MySQL 5.6 implementerar en odokumenterad avståndsfunktion st_distance(p1, p2)
. Den här funktionen returnerar dock kartesiska avstånd. Så det är helt olämpligt för latitud- och longitudbaserade beräkningar. På tempererade breddgrader täcker en latitud nästan dubbelt så mycket ytavstånd (nord-syd) som en longitud (öst-västlig), eftersom latitudlinjerna växer närmare varandra närmare polerna.
Så en cirkulär närhetsformel måste använda äkta latitud och longitud.
I din applikation kan du hitta alla flags
punkter inom tio lagstadgade miles från en given latpoint,longpoint
med en fråga som denna:
SELECT id, coordinates, name, r,
units * DEGREES(ACOS(LEAST(1.0, COS(RADIANS(latpoint))
* COS(RADIANS(latitude))
* COS(RADIANS(longpoint) - RADIANS(longitude))
+ SIN(RADIANS(latpoint))
* SIN(RADIANS(latitude))))) AS distance
FROM flags
JOIN (
SELECT 42.81 AS latpoint, -70.81 AS longpoint,
10.0 AS r, 69.0 AS units
) AS p ON (1=1)
WHERE MbrContains(GeomFromText (
CONCAT('LINESTRING(',
latpoint-(r/units),' ',
longpoint-(r /(units* COS(RADIANS(latpoint)))),
',',
latpoint+(r/units) ,' ',
longpoint+(r /(units * COS(RADIANS(latpoint)))),
')')), coordinates)
Om du vill söka efter punkter inom 20 km, ändra denna rad i frågan
20.0 AS r, 69.0 AS units
till detta, till exempel
20.0 AS r, 111.045 AS units
r
är radien i vilken du vill söka. units
är avståndsenheterna (mil, km, furlongs, vad du vill) per latitudgrad på jordens yta.
Den här frågan använder en avgränsande lat/längd tillsammans med MbrContains
för att utesluta punkter som definitivt är för långt från din startpunkt använder du sedan formeln för storcirkelavstånd för att generera avstånden för de återstående punkterna. En förklaring av allt detta finns här
. Om din tabell använder MyISAM-åtkomstmetoden och har ett rumsligt index, MbrContains
kommer att utnyttja det indexet för att få dig att söka snabbt.
Slutligen väljer frågan ovan alla punkter inom rektangeln. För att begränsa det till endast punkterna i cirkeln och sortera dem efter närhet, avsluta frågan så här:
SELECT id, coordinates, name
FROM (
/* the query above, paste it in here */
) AS d
WHERE d.distance <= d.r
ORDER BY d.distance ASC