sql >> Base de Datos >  >> RDS >> Mysql

Puntos de consulta dentro de un radio dado en MySQL

Para MySQL 5.7+

Dado que tenemos la siguiente tabla simple,

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

create spatial index example_lnglat 
    on example (lnglat);

Con los siguientes datos simples,

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));

Obtendría los puntos dentro de un rango dado de otro punto (nota:tenemos que buscar dentro de un polígono) con la siguiente combinación de funciones st:

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);

Debería ver algo como esto como resultado:

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

Como referencia sobre la distancia, si eliminamos la restricción, el resultado del punto de prueba se ve así:

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

Nota 1 :el campo se llama lnglat ya que ese es el orden correcto si piensa en los puntos como (x, y) y también es el orden en que la mayoría de las funciones (como el punto) aceptan el parámetro

Nota 2 :en realidad no puede aprovechar los índices espaciales si usara círculos; también tenga en cuenta que el campo de punto se puede configurar para aceptar nulo, pero los índices espaciales no pueden indexarlo si es anulable (se requiere que todos los campos en el índice no sean nulos).

Nota 3 :st_buffer se considera (según la documentación) como malo para este caso de uso

Nota 4 :las funciones anteriores (en particular, st_distance_sphere) están documentadas como rápidas pero no necesariamente súper precisas; si sus datos son muy sensibles a eso, agregue un poco de margen de maniobra a la búsqueda y ajuste el conjunto de resultados