2016-09-20 20 views
1

我剛剛使用地理數據類型,但我已經想出瞭如何使用它從一個點獲取郵編列表(在存儲過程中,我只是把它指向了varchar我提供了「經度緯度」),這非常棒。從地理存儲過程獲得里程

但是,我需要能夠展示的下一個東西大概是距離這些點的距離。我看了幾個答案,找不到任何東西。

這裏是我的存儲過程:

ALTER PROCEDURE [dbo].[GetZipCodesByDistance] 
@point varchar(500), 
@distance int 
AS 
BEGIN 
SET NOCOUNT ON; 

declare @geoPoint geography 
set @geoPoint = geography::STGeomFromText('POINT (' + @point + ')', 4326) 
          .STBuffer(@distance/0.0006213712) 
SELECT zc.zip_id AS ZipId 
     ,zc.zip_code AS ZipCodeId 
     ,zc.zip_type AS ZipType 
     ,zc.zip_city AS ZipCity 
     ,zc.zip_utc AS ZipUtc 
     ,zc.zip_dst AS ZipDst 
     ,zc.zip_latitude AS ZipLatitude 
     ,zc.zip_longitude AS ZipLongitude, 
     (Geo.MakeValid()).STDistance(@geoPoint) 
FROM zip_code zc 
WHERE zc.Geo.STIntersects(@geoPoint) = 1 

所以,我的問題是...我怎麼得到它從點返回哩?我試圖添加列「(Geo.MakeValid()).STDistance(@geoPoint)」,但它返回全零。

謝謝你的幫助!

AJ

+0

那麼你的問題是什麼?請閱讀[** How-to-Ask **](http://stackoverflow.com/help/how-to-ask) \t \t這裏是[** START **](http ://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/),瞭解如何提高您的問題質量並獲得更好的答案。 –

+0

對不起,我不明確,我編輯我的帖子,有問題在那裏。謝謝! – ajtatum

回答

1

試試這個

SELECT geography::STGeomFromText('POINT(' + zc.zip_latitude 
            + ' ' + zc.zip_longitude + ')' 
           , 4326).STDistance(@geoPoint); 
+0

這讓我非常接近,我不得不將zip_latitude和zip_longitude轉換爲VARCHAR(50),現在距離列出現在「13489758.0063597」我試圖用1609.344分隔它,但距離回到了8382.31166576187,這是不正確的風格。有什麼想法嗎? – ajtatum

+0

Damien_The_Unbeliever讓我更接近,但由於某些原因,存儲過程中的距離值顯示爲英里。但是,它不會轉移到Web應用程序。有任何想法嗎? – ajtatum

+0

我不明白,函數'Geo.MakeValid()'是'地理'一個表字段? –

1

我還是不明白什麼是真正的你的要求。我們有類似的要求來查找郵政編碼之間的距離。看到做的工作樣本函數

CREATE FUNCTION Wrk.ZipDistance 
(
    @Zip1 VARCHAR(20) 
    ,@Zip2 VARCHAR(20) 
) 
RETURNS FLOAT 
AS 
BEGIN 
    DECLARE @LatLong1 GEOGRAPHY 
    DECLARE @LatLong2 GEOGRAPHY 
    DECLARE @Result FLOAT 
    SELECT 
     @LatLong1 = LatLong 
    FROM 
     PostalCode 
    WHERE 
     PostalCode = @Zip1 

    SELECT 
     @LatLong2 = LatLong 
    FROM 
     PostalCode 
    WHERE 
     PostalCode = @Zip2 

    SELECT @Result = @Lat1.STDistance(@Lat2) 

    RETURN @Result/1000 
END 

希望這有助於

0

我建議引入一個獨立的變量來保存與您的緩衝區域:

ALTER PROCEDURE [dbo].[GetZipCodesByDistance] 
@point varchar(500), 
@distance int 
AS 
BEGIN 
SET NOCOUNT ON; 

declare @geoPoint geography 
set @geoPoint = geography::STGeomFromText('POINT (' + @point + ')', 4326); 

declare @searchArea geography 
set @searchArea = @geoPoint.STBuffer(@distance/0.0006213712) 

select zc.zip_id AS ZipId 
     ,zc.zip_code AS ZipCodeId 
     ,zc.zip_type AS ZipType 
     ,zc.zip_city AS ZipCity 
     ,zc.zip_utc AS ZipUtc 
     ,zc.zip_dst AS ZipDst 
     ,zc.zip_latitude AS ZipLatitude 
     ,zc.zip_longitude AS ZipLongitude, 
     (Geo.MakeValid()).STDistance(@geoPoint) 
     FROM zip_code zc 
where zc.Geo.STIntersects(@searchArea) = 1 

I tried to add the column "(Geo.MakeValid()).STDistance(@geoPoint)" but it returns all zeros.

以前,您是在計算找到的點和搜索區域之間的距離 - 這是當然是0,因爲我們已經建立了(通過STIntersects)他們在區域內。所以我改變了事情,以便STDistance通話使用的是點而不是區域。 (當然,我也建議,如果可能的話,存儲過程的參數被改變,以便通過一個已經構建的geography而不是一個字符串,但這可能並不總是可能的)

+0

這在SQL中完美工作。但是,當我從MVC應用程序調用存儲過程時,它返回0.在我的模型中,我有:[NotMapped] public double Distance {get;組; }。我更改了SQL查詢,以便最後的「列」作爲距離返回。任何想法我做錯了什麼? – ajtatum

+0

您向我展示的第一個代碼是屬性'NotMapped' –

+0

找到了一些有趣的東西。在DbContext中,我有以下內容:var query = this.Database.SqlQuery ( 「GetZipCodesByDistance @point,@ distance」, new SqlParameter(「point」,point), new SqlParameter(「distance」,distance) ); 返回查詢; 其中,在調試中運行它時,出現錯誤:SqlParameter已被另一個SqlParameterCollection包含。 – ajtatum

0

好的,想出了一個方法來完成這項工作。

存儲過程是這樣的:

ALTER PROCEDURE [dbo].[GetZipCodesByDistance] @point VARCHAR(500), 
@distance INT 
AS 
BEGIN 
SET NOCOUNT ON; 
DECLARE @geoPoint GEOGRAPHY 
SET @geoPoint = GEOGRAPHY::STGeomFromText('POINT (' + @point + ')', 4326); 

DECLARE @searchArea GEOGRAPHY 
SET @searchArea = @geoPoint.STBuffer(@distance/0.0006213712) 

DECLARE @ZipDistance TABLE(
ZipCode VARCHAR(5), 
ZipLatitude DECIMAL(9,6), 
ZipLongitude DECIMAL(9,6), 
Distance DECIMAL(9,2) 
) 

INSERT INTO @ZipDistance 
SELECT 
     zc.zip_code AS ZipCode 
     ,zc.zip_latitude AS ZipLatitude 
     ,zc.zip_longitude AS ZipLongitude 
     ,CAST((((Geo.MakeValid()).STDistance(@geoPoint))/1609.34) AS DECIMAL(9,2)) AS Distance 
FROM zip_code zc 
WHERE zc.Geo.STIntersects(@searchArea) = 1 

SELECT * FROM @ZipDistance 
END 

然後,我創建了一個模型:

public class ZipCodeWithDistance 
{ 
    public string ZipCode { get; set; } 
    public decimal ZipLatitude { get; set; } 
    public decimal ZipLongitude { get; set; } 
    public decimal Distance { get; set; } 
} 

在的DbContext,我有以下幾點:

public List<ZipCodeWithDistance> GetZipCodes(string point, int distance) 
{ 
    var zipCodes = this.Database.SqlQuery<ZipCodeWithDistance>(
    "GetZipCodesByDistance @point, @distance", 
    new SqlParameter("point", point), 
    new SqlParameter("distance", distance) 
    ).ToList(); 

    return zipCodes; 
} 

在FacilityModel,我有:

[NotMapped] 
public decimal Distance { get; set; } 

最後,在服務,我有以下幾點:如果

public IQueryable<Facility>GetFacilitiesByZipCodes(List<ZipCodeWithDistance> zipCodes) 
{ 
    var zipCodeName = zipCodes.Select(x => x.ZipCode).ToList(); 
    var facilities = oandpDbContext.Facilities.Where(x => zipCodeName.Contains(x.ZipCode.Substring(0, 5))).ToList(); 
    facilities.ForEach(x => 
    { 
     var zip = zipCodes.FirstOrDefault(y => y.ZipCode == x.ZipCode.Substring(0, 5)); 
     if (zip != null) 
     { 
      x.Distance = zip.Distance; 
     } 
    }); 
return facilities.AsQueryable(); 
} 

不知道它的完成這件事的最佳/最有效的方式,但它的作品。任何想法或意見歡迎!謝謝,AJ