代码之家  ›  专栏  ›  技术社区  ›  gjb

MySQL中给定半径内的查询点

  •  9
  • gjb  · 技术社区  · 16 年前

    CREATE TABLE `points` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(128) NOT NULL,
      `location` point NOT NULL,
      PRIMARY KEY (`id`),
      SPATIAL KEY `location` (`location`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
    

    我想问:

    • 一个区域内的所有点 N
    • 每个返回点到给定点的距离

    4 回复  |  直到 10 年前
        1
  •  6
  •   srcspider    10 年前

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

    使用以下简单数据,

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

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

    你应该看到这样的结果:

    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
    

    对于距离参考,如果移除约束,测试点的结果如下所示:

    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
    

    :该字段称为lnglat,因为如果将点视为(x,y),这是正确的顺序,而且也是大多数函数(如point)接受参数的顺序

    :如果要使用圆,则实际上无法利用空间索引;还要注意的是,可以将点字段设置为接受null,但是如果可以为null,则空间索引不能对其进行索引(索引中的所有字段都必须为非null)。

    附注3 :st\u buffer被(文档)认为不适合这个用例

    :上述函数(特别是st_distance_sphere)记录得很快,但不一定超精确;如果您的数据对此非常敏感,请为搜索添加一些回旋空间,并对结果集进行一些微调

        2
  •  3
  •   gjb    16 年前
        3
  •  2
  •   LukáÅ¡ Lalinský    16 年前

    半径不能有效地转位。应该使用边界矩形快速获取可能要查找的点,然后过滤半径以外的点。

        4
  •  0
  •   dexxtr    12 年前

    SELECT 
        *
    FROM 
        `locator`
    WHERE
        SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`
    

    详细信息和一个更多的示例查询 http://dexxtr.com/post/83498801191/how-to-determine-point-inside-circle-using-mysql ,希望这有帮助