【问题标题】:Getting miles from Geography Stored Procedure从地理存储过程中获取里程
【发布时间】:2017-01-28 10:25:58
【问题描述】:

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

【问题讨论】:

  • 那么你的问题是什么?请阅读How-to-Ask 这里是START 了解如何提高问题质量并获得更好答案的好地方。
  • 对不起,我没有明确表示,我已经编辑了我的帖子,以便在其中包含问题。谢谢!

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


【解决方案1】:

试试这个

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

【讨论】:

  • 这让我非常接近,我必须将 zip_latitude 和 zip_longitude 转换为 VARCHAR(50),现在距离列显示在“13489758.0063597”我尝试将其除以 1609.344,但距离又回来了作为 8382.31166576187 这是不正确的样式。有什么想法吗?
  • Damien_The_Unbeliever 让我更接近,但由于某种原因,存储过程中的距离值显示英里。但是,它不会转移到 Web 应用程序。有什么想法吗?
  • 我不明白Geo.MakeValid()这个函数是Geo一个表字段?
【解决方案2】:

我仍然不明白您的实际要求是什么。我们有类似的要求来查找邮政编码之间的距离。查看完成工作的示例函数

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

希望对你有帮助

【讨论】:

    【解决方案3】:

    我建议引入一个单独的变量来保存 point 与您的缓冲区:

    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)”,但它返回全零。

    之前您正在计算找到的点与搜索区域之间的距离——这当然是 0,因为我们已经(通过STIntersects)确定它们在该区域内。所以我改变了一些事情,以便STDistance 调用使用的是点而不是区域。

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

    【讨论】:

    • 这在 SQL 中完美运行。但是,当我从 MVC 应用程序调用存储过程时,它返回 0。在我的模型中,我有: [NotMapped] public double Distance { get;放; }。我更改了 SQL 查询,以便最后一个“列”作为距离返回。知道我做错了什么吗?
    • 你给我看的第一段代码是属性NotMapped
    • 发现了一些有趣的东西。在 DbContext 中,我有以下内容: var query = this.Database.SqlQuery("GetZipCodesByDistance @point, @distance", new SqlParameter("point", point), new SqlParameter("distance", distance) ) ;返回查询;其中,在调试中运行它时,我收到错误:SqlParameter 已包含在另一个 SqlParameterCollection 中。
    • 完整的 Facility 类可以在这里找到:gist.github.com/ajtatum/88ff2c3bd426e9c0f58fa290f3cf99ad
    【解决方案4】:

    好的,想出了一个方法来完成这项工作。

    存储过程如下:

    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();
    }
    

    不确定这是否是完成这项工作的最佳/最有效的方法,但它确实有效。欢迎任何想法或cmets!谢谢你,AJ

    【讨论】:

      猜你喜欢
      • 2017-01-01
      • 2016-08-04
      • 2018-03-04
      • 2011-04-26
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-21
      相关资源
      最近更新 更多