2

我正在一個項目中,我有我的數據庫中存儲有經度和緯度座標的地方。我使用Google地圖將這些地點標記爲地圖上的標記。我不想將任何「不可見」標記(當前視口/邊界框外的標記)繪製到地圖上。因此我遵循Googles advice regarding viewport marker management存儲過程獲取邊界框內的所有點考慮負經度

我在那裏我使用AJAX來查詢每當我的地圖檢視已經改變了一個ASP.NET Web服務的工作方案。此Web服務調用MSSQL數據庫中的存儲過程以獲取當前視口/邊界框內具有座標的所有位置。該存儲過程是這樣的:

ALTER PROCEDURE dbo.GetPlacesInsideBoundingBox 

    (
    @swLat VarChar(11), /* south-west point latitude */ 
    @swLng VarChar(11), /* south-west point longitude */ 
    @neLat VarChar(11), /* north-east point latitude */ 
    @neLng VarChar(11) /* north-east point longitude */ 
    ) 

AS 
    /* SET NOCOUNT ON */ 

    SELECT * FROM dbo.Place WHERE 
    place_lat >= CONVERT(Decimal(11,8), @swLat) 
    AND place_lat <= CONVERT(Decimal(11,8), @neLat) 
    AND place_lng >= CONVERT(Decimal(11,8), @swLng) 
    AND place_lng <= CONVERT(Decimal(11,8), @neLng) 
    RETURN 

發送到存儲過程的參數是簡單的西南部和視口的東北角/邊框的經度和緯度。然後我將這些點與存儲在我的數據庫中的經度和緯度值進行比較,以查看哪些位置在當前視口/邊界框內。

這工作正常!但是我讀到,如果你對經度(Prime Prime子以西)有負值,並且簡單的解決方案是在經度爲負值的情況下增加360度,那麼你會遇到問題。

我有兩個問題:

  1. 我如何改變我的存儲過程(上圖)考慮到負 經度?

  2. 有沒有其他修改我應該考慮做到這個 存儲過程,使其萬無一失?

如果你想知道從VARCHAR到十進制的轉換,我發現它更容易與客戶端簡單的字符串(JavaScript)的工作,然後將其轉換爲十進制數的我的存儲過程,當我需要做計算。

在此先感謝!

+0

謝謝你這個鼓舞人心的問題和有用的鏈接!我可能會用同樣的方法! – TMS

回答

1

其實我找到了更好的解決方案。 SQL Server具有用於處理空間數據的內置數據類型。所以我給我的表添加了一個新值,並將其稱爲place_geo與地理數據類型。然後我用地理點填充它(根據我在數據庫中已經有的緯度和經度創建)。當我在數據庫中將點存儲爲地理點時,存儲過程的語法變得簡單多了,我也認爲它會更快地執行。

這裏是我的存儲過程:

ALTER PROCEDURE dbo.GetPlaceClosestToMe 
    (
    @my_lat Decimal(11,8), 
    @my_lng Decimal(11,8) 
    ) 
AS 
    DECLARE @my_point geography; 
    SET @my_point = geography::Point(@my_lat, @my_lng , 4326); /* SRID 4326 */ 
    SET NOCOUNT ON 

    SELECT TOP 1 
     place_id, 
     place_name, 
     @my_point.STDistance(place_geo)/1000 [Distance in km] 
FROM Places 
ORDER BY @my_point.STDistance(place_geo) 

那麼它有什麼作用? 首先我得到一個經度和緯度作爲十進制格式的輸入參數。我聲明瞭一個新的變量(@my_point),其數據類型爲「geography」。然後,我使用經度和緯度輸入參數爲剛創建的變量分配一個新的地理點。

然後我要求我的數據庫表(place_geo)中最接近@my_point的點。 (STDistance返回兩種地理類型之間的最短線)。除以1000將得到用公里表示的距離。

如果你希望它返回幾個結果,只是改變了選擇:SELECT TOP 5或SELECT TOP 10

目前,我沒有足夠的測試數據來測試,如果這是比使用更快老方法,但也許別人做了一些測試?我猜想使用地理數據類型比舊方法快得多。

使用我有限的測試數據,舊的存儲過程和這個新的存儲過程返回相同的結果。

希望你發現這個後續有用!

1

1)經度normaly應該是-180到180之間,以使剛剛檢查,如果從谷歌座標滿足此條件。可能是。如果沒有,只需通過添加或減去360來將它們標準化爲在此間隔內。在調用存儲過程之前,將它們標準化爲

2)通常@swLng <= @neLng,但你也必須處理的情況下@swLng > @neLng。所以存儲過程裏面,您的經度狀況會是什麼樣子:

AND 
(
    (CONVERT(Decimal(11,8), @swLng) <= CONVERT(Decimal(11,8), @neLng) 
     AND place_lng >= CONVERT(Decimal(11,8), @swLng) 
     AND place_lng <= CONVERT(Decimal(11,8), @neLng) 
    ) 
    OR 
    (CONVERT(Decimal(11,8), @swLng) > CONVERT(Decimal(11,8), @neLng) 
     AND (place_lng >= CONVERT(Decimal(11,8), @swLng) 
      OR place_lng <= CONVERT(Decimal(11,8), @neLng)) 
    ) 
) 

PS:需要注意的是,你應該使用GIS喜歡的PostGIS這是真正有效:)我正要解決這個問題,但我仍然推遲「直到我有一個GIS」。你啓發了我,也許我也會去解決這個問題。

P.S .:我不確定你的數據庫引擎是如何優化的,但我想提高效率可能如果你將緯度和經度定義爲索引,這樣可以更快地解決問題。但我不確定。

+0

感謝您的回覆!我已經查看了SQL Server中的地理數據類型,但我需要一些快速和骯髒的東西。如果你有興趣,看看:http://msdn.microsoft.com/en-us/library/bb895266.aspx – tkahn

+0

@tkahn,是的,我認爲快速和骯髒的解決方案可能是有效的,如果你沒有像數以百萬計的標記......一旦你做到了,請讓我知道在這裏,如果可能的話可能會發佈一個鏈接。我對這個解決方案感興趣! – TMS