2009-11-06 85 views
2

給定一個表的用戶,由於緯度和經度,找到感興趣的是位置

+-----+---------+---------+---------+---------+---------+ 
| user| min_lat | max_lat | min_lng | max_lng | 
+-----+---------+---------+---------+---------+---------+ 
| a | 46 |  407 |  6 |  367 | 
| b | 226 |  227 |  186 |  188 | 

與點(X,Y)查找用戶,其中一點是最小和最大的經度和緯度範圍內用戶(其中​​min和max long和lat =當前位置減去或加上半徑)。

最小值可以小於0,最大值可以大於360,查詢需要考慮這些因素。

E.g.使用Point(7,5)進行過濾也應該返回用戶A,因爲367-360 = 7。

不知道我是否得到這個權利,但希望有人能給我一些見解。

+0

點(4,5)是一個更好的實例中,如圖7是在範圍6..367(不考慮a == b mod 360)。 4在範圍之外,但在a區域之內。此外,每個點都在該地區(6..367,46..407);也許(50..367,46..407)是一個更好的測試區域,因爲經度範圍排除了一些值,但是緯度沒有。此外,這些地區是否包含終點?術語「最小」和「最大」暗示它們是,但最好是明確的。 – outis 2009-11-11 07:30:15

回答

0

要回答你的查詢的一部分,如果你說367和7是相同的,我同樣假定727也是。

因此,你要使用360的模數。餘數除以360.

例如(其中,%是C#和C++的語法,你可能會發現一個SQL的方式來做到這一點)

7 % 360 = 7 
367 % 360 = 7 
727 % 360 = 7 

看起來像SELECT b MOD 360 from table;是你想要的那種東西。

0

我懷疑有一個更優雅的答案,但我認爲SQL where子句的限制使得這一點更加困難。

假設:

  • 0 <= x < 360
  • 0 <= y < 360
  • max_lat - min_lat <= 361
  • max_lng - min_lng <= 361
SELECT user FROM user_location WHERE 
((min_lat < 0 AND ((0 <= y AND y <= max_lat) OR (min_lat + 360 <= y AND y < 360))) OR 
(min_lat >= 0 AND ((min_lat <= y AND y <= max_lat) OR (0 <= y AND y <= max_lat - 360)))) 
AND 
((min_lng < 0 AND ((0 <= x AND x <= max_lng) OR (min_lng + 360 <= x AND x <= 360))) OR 
(min_lng >= 0 AND ((min_lng <= x AND x <= max_lng) OR (0 <= x AND x <= max_lng - 360)))) 

如果min> = 0,那麼x必須落在min和max之間,或者它必須落在0和max - 360.

爲了清楚起見,提供了上述格式。如果將360的加法和減法移到x和y參數中,則比較會變得恆定,並可能顯着加快查詢速度。

+0

完成使用此,謝謝! – user167206 2009-11-29 21:48:54

0

使用模數來確保所有值都介於0和360之間,並且查詢變得非常簡單。假設{pointLat}和{pointLng}是被過濾的點的座標。

SELECT * 
FROM table 
WHERE IF(min_lat < max_lat, 
     MOD({pointLat}, 360) BETWEEN MOD(min_lat, 360) AND MOD(max_lat, 360)), 
     MOD({pointLat}, 360) NOT BETWEEN MOD(min_lat, 360) AND MOD(max_lat, 360))) 
    AND IF(min_lng < max_lng, 
     MOD({pointLng}, 360) BETWEEN MOD(min_lng, 360) AND MOD(max_lng, 360)), 
     MOD({pointLng}, 360) NOT BETWEEN MOD(min_lng, 360) AND MOD(max_lng, 360))); 

雖然這可行,但我強烈建議在SQL查詢之外執行MOD計算或添加具有規範化值的額外列。在這段代碼中使用MOD函數將阻止查詢利用這些列上的任何索引。

+0

如果min = 350,max = 370,point = 2,則比較變成「我在350和10之間」,但我認爲它不會匹配。 – 2009-11-08 16:11:41

+0

查詢更新以正確處理該案件。 – jonthornton 2009-11-08 20:58:15

+0

現在您有:MOD(370360)和MOD(350,360) 之間MOD(350,360)和MOD(370360)之間的 MOD(2360)... OR MOD(2360)成爲 2 350和10之間或 2 10和350之間 哪些仍然不符合標準。 – 2009-11-10 22:47:21

2

我建議將表中存儲的緯度&經度值限制在[0,360]的範圍內。在插入和更新之前創建觸發器,以強制執行mod 360等效,如果max-min> 360,則分別將最小值和最大值分別設置爲0和360。例如:

delimiter ;; 

CREATE TRIGGER normalize_inserted_ranges BEFORE INSERT 
    ON table 
    FOR EACH ROW BEGIN 
    IF NEW.max_lat - NEW.min_lat >= 360 THEN 
     SET NEW.min_lat=0; 
     SET NEW.max_lat=360; 
    ELSE 
     SET NEW.min_lat = NEW.min_lat % 360; 
     SET NEW.max_lat = NEW.max_lat % 360; 
    END IF; 
    IF NEW.max_lng - NEW.min_lng >= 360 THEN 
     SET NEW.min_lng=0; 
     SET NEW.max_lng=360; 
    ELSE 
     SET NEW.min_lng = NEW.min_lng % 360; 
     SET NEW.max_lng = NEW.max_lng % 360; 
    END IF; 
    END 
;; 
delimiter ; 

然後可以使用以下查詢:

SELECT user FROM table 
    WHERE 
     IF(min_lng <= max_lng, 
     @x BETWEEN min_lng AND max_lng, 
     @x <= max_lng OR min_lng <= @x) 
    AND 
     IF(min_lat <= max_lat, 
     @y BETWEEN min_lat AND max_lat, 
     @y <= max_lat OR min_lat <= @y) 
; 
+0

我喜歡你的解決方案。我的一個擔憂是你失去了信息。從最初的問題來看很難說最終的意圖是什麼,但似乎改變價值觀可能會抹去有價值的信息。我認爲很容易保留原始數據並存儲修改過的數據以便以更快的搜索速度來犧牲額外的存儲空間。幹得不錯! – 2009-11-13 07:46:49

+0

有關其他數據使用問題的(缺少)要求留下一些空間來更改存儲表示。關於將這兩種形式作爲時間/空間折衷存儲的關鍵點。 – outis 2009-11-15 04:27:27