2016-09-20 59 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