8

道路やホテルに関するデータを保存するために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 クエリとはどのようなもので、どのようにデータを後処理するのでしょうか?

4

3 に答える 3

2

データベースには次の 2 つの関数を作成できます。

  1. 距離 : これにより、2 点間の距離が得られます
  2. DistanceFromLine : ここでは、直線上の各点から距離が計算され、最短距離が得られます。

ポイントとラインの間の距離を比較し、最短のものを選択します。

ここに距離関数があります


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//

于 2013-01-23T13:12:57.357 に答える