使用MySQL Spatial Extensions从一个点找到N个最近的LineString

时间:2012-10-02 03:29:11

标签: mysql geospatial

我正在使用MySQL Spatial Extensions来存储有关道路和酒店的数据。我将酒店数据存储为Point,同时将道路数据存储为LineString。表格看起来像这样

CREATE TABLE IF NOT EXISTS `Hotels` (
    `id` int unsigned NOT NULL AUTO_INCREMENT,
    `name` text,
    `coordinate` point NOT NULL,
    PRIMARY KEY (`id`),
    SPATIAL KEY `coordinate` (`coordinate`),
)

CREATE TABLE IF NOT EXISTS `Roads` (
    `id` int unsigned NOT NULL AUTO_INCREMENT,
    `name` text,
    `route` linestring NOT NULL,
    PRIMARY KEY (`id`),
    SPATIAL KEY `coordinate` (`route`),
)

实例的可视化将是这样的。

http://i.stack.imgur.com/8IVVA.png

我的问题是给出一个数字N和一个点P,从点P找到N个最近的道路的SQL查询是什么?该距离由道路中的一段到如上所示的点之间的最小垂直距离来定义。 (虽然在现实中,最近的距离应该在高速公路大门和酒店之间,但在这种情况下,我们可以从任何一点进入高速公路:P)

如果没有针对此问题的单个SQL语句解决方案,则可以接受中间SQL查询和后处理。但是什么是有效的SQL查询以及如何对数据进行后处理?

3 个答案:

答案 0 :(得分:2)

您可以在数据库中创建两个函数:

  1. 距离:这将为您提供两点之间的距离
  2. DistanceFromLine:此处距离将从行中的每个点计算,并为您提供最短距离。
  3. 比较点和线之间的距离,选择最短的距离。

    这是距离函数


    delimiter //
    
    CREATE FUNCTION distance (latA double, lonA double, latB double, LonB double)
    RETURNS double DETERMINISTIC
        BEGIN
            SET @RlatA = radians(latA);
            SET @RlonA = radians(lonA);
            SET @RlatB = radians(latB);
            SET @RlonB = radians(LonB);
            SET @deltaLat = @RlatA - @RlatB;
            SET @deltaLon = @RlonA - @RlonB;
            SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) +
            COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2);
            RETURN 2 * ASIN(SQRT(@d)) * 637101;
        END//
    

    这是DistanceFromLine函数:


    DROP function IF EXISTS `DistanceFromLine`;
    delimiter //
        CREATE FUNCTION `DistanceFromLine`(
        route LINESTRING, point1 POINT
        ) RETURNS INT DETERMINISTIC
            BEGIN
            DECLARE a INT Default 0 ;
            DECLARE minDistance INT Default 0;
            DECLARE currentDistance INT Default 0;
            DECLARE currentpoint point ;
            DECLARE size INT Default 0 ;
            SET size =  NumPoints(route);
                  simple_loop: LOOP
           SET a = a+1;
           SET currentpoint = PointN(route,a);
           SET currentDistance = Distance(X(point1), Y(point1),       
                   X(currentpoint),Y(currentpoint));
    
           IF a = 1 THEN
            SET minDistance = currentDistance;
               END IF;
    
           IF currentDistance < minDistance THEN
            SET minDistance = currentDistance;
           END IF;
           IF a=size THEN
                     LEAVE simple_loop;
           END IF;
              END LOOP simple_loop;
         RETURN (minDistance);
     END//
    

答案 1 :(得分:1)

对我来说,这是一个非常有用的答案,但我使用的是MySQL 5.7.18,它具有更高级或更不同的地理查询功能。已发布的距离函数不再需要 - 使用ST_Distance_Sphere。所以这里有一个相同代码的更新,使DistanceFromLine符合现代(5.7.6+)MySQL ......

DROP function IF EXISTS `DistanceFromLine`;
delimiter //
    CREATE FUNCTION `DistanceFromLine`(
    route LINESTRING, point1 POINT
    ) RETURNS INT DETERMINISTIC
        BEGIN
        DECLARE a INT Default 0 ;
        DECLARE minDistance INT Default 0;
        DECLARE currentDistance INT Default 0;
        DECLARE currentpoint point ;
        DECLARE size INT Default 0 ;
        SET size =  ST_NumPoints(route);
              simple_loop: LOOP
       SET a = a+1;
       SET currentpoint = ST_PointN(route,a);
       SET currentDistance = ST_Distance_Sphere(point1,currentpoint);

       IF a = 1 THEN
        SET minDistance = currentDistance;
           END IF;

       IF currentDistance < minDistance THEN
        SET minDistance = currentDistance;
       END IF;
       IF a=size THEN
                 LEAVE simple_loop;
       END IF;
          END LOOP simple_loop;
     RETURN (minDistance);
 END//

答案 2 :(得分:0)

我一直在研究这个问题,但遗憾的是找到最近的酒店之路是一个不利的解决方案。我发现道路上的入口是明确的答案。换句话说就是地址。 这意味着拥有一个地址表并匹配最近地址道路的点。