sql >> Database teknologi >  >> RDS >> Mysql

Brug MySQL rumlige udvidelser til at vælge punkter inde i cirklen

Der er ingen geospatiale udvidelsesfunktioner i MySQL, der understøtter afstandsberegninger for breddegrad/længde. Der er fra MySQL 5.7 .

Du beder om nærhedscirkler på jordens overflade. Du nævner i dit spørgsmål, at du har lat/lang værdier for hver række i dine flags tabel, og også universal tværgående Mercator (UTM) projekterede værdier i en af ​​flere forskellige UTM-zoner . Hvis jeg husker mine UK Ordnance Survey-kort korrekt, er UTM nyttig til at lokalisere genstande på disse kort.

Det er en simpel sag at beregne afstanden mellem to punkter i samme zone i UTM:den kartesiske afstand gør det trick. Men når punkter er i forskellige zoner, virker den beregning ikke.

For den applikation, der er beskrevet i dit spørgsmål, er det derfor nødvendigt at bruge Great Circle Distance , som beregnes ved hjælp af haversin eller en anden passende formel.

MySQL, forstærket med geospatiale udvidelser, understøtter en måde at repræsentere forskellige plane former (punkter, polylinjer, polygoner og så videre) som geometriske primitiver. MySQL 5.6 implementerer en udokumenteret afstandsfunktion st_distance(p1, p2) . Denne funktion returnerer dog kartesiske afstande. Så det er helt uegnet til bredde- og længdegradsbaserede beregninger. På tempererede breddegrader strækker en breddegrad sig næsten dobbelt så meget overfladeafstand (nord-syd) som en længdegrad (øst-vest), fordi breddegradslinjerne vokser tættere sammen tættere på polerne.

Så en cirkulær nærhedsformel skal bruge ægte bredde- og længdegrad.

I din applikation kan du finde alle flags punkter inden for ti statut miles fra et givet latpoint,longpoint med en forespørgsel som denne:

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)

Hvis du vil søge efter punkter inden for 20 km, skal du ændre denne linje i forespørgslen

               20.0 AS r, 69.0 AS units
 

hertil f.eks.

               20.0 AS r, 111.045 AS units
 

r er den radius, du vil søge i. units er afstandsenhederne (miles, km, furlongs, hvad end du vil) pr. breddegrad på jordens overflade.

Denne forespørgsel bruger en afgrænsende lat/lang sammen med MbrContains for at udelukke punkter, der bestemt er for langt fra dit udgangspunkt, bruger du derefter storcirkelafstandsformlen til at generere afstandene for de resterende punkter. En forklaring på alt dette kan findes her . Hvis din tabel bruger MyISAM-adgangsmetoden og har et rumligt indeks, MbrContains vil udnytte det indeks til at få dig til at søge hurtigt.

Til sidst vælger forespørgslen ovenfor alle punkter i rektanglet. For at indsnævre det til kun punkterne i cirklen og sortere dem efter nærhed, skal du afslutte forespørgslen sådan her:

 SELECT id, coordinates, name
   FROM (
         /* the query above, paste it in here */
        ) AS d
  WHERE d.distance <= d.r
  ORDER BY d.distance ASC 
 


  1. Vigtigheden af ​​at vælge den rigtige Azure VM-størrelse

  2. Hvad er formålet med et Android-projektionskort i en indholdsudbyder?

  3. Lær, hvordan du sikkerhedskopierer din MySQL-database

  4. DBCA Opret database dårlig REMOTE_LISTENER