从地理存储过程中获取里程数

时间:2016-09-20 13:10:27

标签: sql-server sql-server-2008 geocoding distance geo

我是使用Geography数据类型的新手,但我已经想出如何使用它从一个点获取一个zipcodes列表(在存储过程中我只是将点作为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

4 个答案:

答案 0 :(得分:1)

试试这个

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

答案 1 :(得分: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

希望这有帮助

答案 2 :(得分: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
  

我尝试添加列"(Geo.MakeValid())。STDistance(@geoPoint)"但它返回全零。

之前您正在计算找到的点与搜索区域之间的距离 - 当然我们已经建立(通过STIntersects)他们&#39 ;在该地区内。所以我改变了一些事情,以便STDistance调用使用的是点而不是区域。

(当然,我还建议,如果可能的话,更改存储过程的参数,以便您传递已经构造的geography而不是字符串。但是这可能并不总是可能的)

答案 3 :(得分: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