使用MySQL Spatial Extensions查找距离某个点最近的N行字符串

使用MySQL Spatial Extensions查找距离某个点最近的N行字符串,mysql,geospatial,Mysql,Geospatial,我正在使用存储有关道路和酒店的数据。我将酒店数据存储为点,而将道路数据存储为线字符串。这些桌子看起来像这样 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` (`coordi

我正在使用存储有关道路和酒店的数据。我将酒店数据存储为点,而将道路数据存储为线字符串。这些桌子看起来像这样

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`),
)
实例的可视化如下所示

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


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

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

  • 距离:这将提供两点之间的距离
  • DistanceFromLine:这里将计算直线中每个点的距离,并将为您提供最短距离
  • 比较点和线之间的距离,选择最短的距离

    这是距离函数



    以下是DistanceFromLine函数:


    DROP函数(如果存在)`DistanceFromLine`;
    分隔符//
    创建函数“DistanceFromLine”`(
    管线线串,点1点
    )返回整数确定性
    开始
    声明一个INT默认值0;
    声明minDistance INT默认值为0;
    声明currentDistance INT默认值为0;
    声明当前点;
    声明大小INT默认值为0;
    设置大小=NumPoints(路由);
    简单循环:循环
    设置a=a+1;
    设置currentpoint=PointN(路由,a);
    设置当前距离=距离(X(点1),Y(点1),
    X(电流点),Y(电流点));
    如果a=1,则
    设置minDistance=当前距离;
    如果结束;
    如果currentDistance


    这对我来说是一个非常有用的答案,但我使用的是MySQL 5.7.18,它有更高级的或只是不同的地理查询功能。发布的距离函数不再需要-使用ST_distance_Sphere。因此,这里更新了相同的代码,使DistanceFromLine与现代(5.7.6+)MySQL兼容

    DROP函数(如果存在)`DistanceFromLine`;
    分隔符//
    创建函数“DistanceFromLine”`(
    管线线串,点1点
    )返回整数确定性
    开始
    声明一个INT默认值0;
    声明minDistance INT默认值为0;
    声明currentDistance INT默认值为0;
    声明当前点;
    声明大小INT默认值为0;
    设置大小=ST_NumPoints(路线);
    简单循环:循环
    设置a=a+1;
    设置currentpoint=ST_PointN(路线,a);
    设置currentDistance=ST_Distance_Sphere(点1,currentpoint);
    如果a=1,则
    设置minDistance=当前距离;
    如果结束;
    如果currentDistance
    我也一直在研究这个问题,但不幸的是,为酒店找到最近的道路是一个不利的解决方案。我发现这条路的入口才是最终的答案。换句话说,就是地址。
    这意味着有一个地址表和匹配点到最近的地址道路

    你得到答案了吗?:)请确保您使用的是MySQL 5.5,否则空间功能的实现不足以回答您的问题
    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//
    
    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//
    
    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//