Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Fragen Sie Punkte innerhalb eines bestimmten Radius in MySQL ab

Für MySQL 5.7+

Angenommen, wir haben die folgende einfache Tabelle,

create table example (
  id bigint not null auto_increment primary key,
  lnglat point not null
);

create spatial index example_lnglat 
    on example (lnglat);

Mit den folgenden einfachen Daten,

insert into example (lnglat) 
values
(point(-2.990435, 53.409246)),
(point(-2.990037, 53.409471)),
(point(-2.989736, 53.409676)),
(point(-2.989554, 53.409797)),
(point(-2.989350, 53.409906)),
(point(-2.989178, 53.410085)),
(point(-2.988739, 53.410309)),
(point(-2.985874, 53.412656)),
(point(-2.758019, 53.635928));

Sie würden die Punkte innerhalb eines bestimmten Bereichs eines anderen Punkts (Hinweis:Wir müssen innerhalb eines Polygons suchen) mit der folgenden Kombination von st-Funktionen erhalten:

set @px = -2.990497;
set @py = 53.410943;
set @range = 150; -- meters
set @rangeKm = @range / 1000;

set @search_area = st_makeEnvelope (
  point((@px + @rangeKm / 111), (@py + @rangeKm / 111)),
  point((@px - @rangeKm / 111), (@py - @rangeKm / 111))
);

select id, 
       st_x(lnglat) lng, 
       st_y(lnglat) lat,
       st_distance_sphere(point(@px, @py), lnglat) as distance
  from example
 where st_contains(@search_area, lnglat);

Als Ergebnis sollten Sie in etwa Folgendes sehen:

3   -2.989736   53.409676   149.64084252776277
4   -2.989554   53.409797   141.93232714661812
5   -2.98935    53.409906   138.11516275402533
6   -2.989178   53.410085   129.40289289527473

Wenn wir die Einschränkung entfernen, sieht das Ergebnis für den Testpunkt wie folgt aus:

1   -2.990435   53.409246   188.7421181457556
2   -2.990037   53.409471   166.49406509160158
3   -2.989736   53.409676   149.64084252776277
4   -2.989554   53.409797   141.93232714661812
5   -2.98935    53.409906   138.11516275402533
6   -2.989178   53.410085   129.40289289527473
7   -2.988739   53.410309   136.1875540498202
8   -2.985874   53.412656   360.78532732013963
9   -2.758019   53.635928   29360.27797292756

Anmerkung 1 :Das Feld heißt lnglat, da dies die richtige Reihenfolge ist, wenn Sie sich Punkte als (x, y) vorstellen, und dies auch die Reihenfolge ist, in der die meisten Funktionen (wie Punkt) den Parameter akzeptieren

Anmerkung 2 :Sie können räumliche Indizes nicht wirklich nutzen, wenn Sie Kreise verwenden würden; Beachten Sie auch, dass das Punktfeld so eingestellt werden kann, dass es null akzeptiert, räumliche Indizes es jedoch nicht indizieren können, wenn es nullfähig ist (alle Felder im Index müssen nicht null sein).

Anmerkung 3 :st_buffer wird (von der Dokumentation) als schlecht für diesen Anwendungsfall angesehen

Anmerkung 4 :Die obigen Funktionen (insbesondere st_distance_sphere) sind als schnell, aber nicht unbedingt supergenau dokumentiert; Wenn Ihre Daten sehr empfindlich darauf reagieren, geben Sie der Suche etwas Spielraum und nehmen Sie eine Feinabstimmung der Ergebnismenge vor