Mysql
 sql >> Base de données >  >> RDS >> Mysql

Interroger des points dans un rayon donné dans MySQL

Pour MySQL 5.7+

Étant donné que nous avons le tableau simple suivant,

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

create spatial index example_lnglat 
    on example (lnglat);

Avec les données simples suivantes,

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

Vous obtiendriez les points dans une plage donnée d'un autre point (remarque :nous devons rechercher à l'intérieur d'un polygone) avec la combinaison suivante de fonctions 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);

Vous devriez voir quelque chose comme ceci :

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

Pour référence sur la distance, si nous supprimons la contrainte, le résultat pour le point de test ressemble à ceci :

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

Remarque 1  :le champ s'appelle lnglat car c'est le bon ordre si vous pensez aux points comme (x, y) et c'est aussi l'ordre dans lequel la plupart des fonctions (comme point) acceptent le paramètre

Remarque 2 :vous ne pouvez pas réellement profiter des index spatiaux si vous deviez utiliser des cercles ; notez également que le champ de point peut être défini pour accepter la valeur nulle, mais les index spatiaux ne peuvent pas l'indexer s'il est nullable (tous les champs de l'index doivent être non nuls).

Remarque 3 :st_buffer est considéré (par la documentation) comme mauvais pour ce cas d'utilisation

Remarque 4 :les fonctions ci-dessus (en particulier st_distance_sphere) sont documentées comme rapides mais pas nécessairement super précises ; si vos données sont très sensibles à cela, ajoutez un peu de marge de manœuvre à la recherche et affinez l'ensemble de résultats