2012-10-02 15 views
8

我使用MySQL Spatial Extensions來存儲有關道路和酒店的數據。我將酒店數據存儲爲Point,而將道路數據存儲爲LineString。表看起來像這樣使用MySQL Spatial Extensions從一個角度查找N個最近的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點,什麼是SQL查詢來找到點P N最近的道路?距離由道路中的一段到上述點之間的最小垂直距離定義。 (儘管在現實中,最近的距離應該在高速公路大門和酒店之間,但在這種情況下,我們可以從任意點進入高速公路:P)

如果沒有單一的SQL語句解決方案問題,中間SQL查詢和後處理對我來說都是可以接受的。但是,什麼是高效的SQL查詢以及如何後處理數據呢?

+0

你得到了答案嗎? :) – bonCodigo

+0

請確保您使用MySQL 5.5,否則空間功能不足以解決您的問題 – TheSteve0

回答

2

您可以在數據庫中創建兩個函數:

  1. 距離:這會給兩點
  2. 你們之間的距離
  3. 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// 

0

這是一個非常有用的向我傾斜,但我使用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// 
0

我一直也正在研究這個問題,但不幸的是找到對酒店最近的道路是不利的解決方案。我發現道路入口處是確定的答案。換句話說,地址。 這意味着有一個地址表和匹配點最近的地址路