2013-07-09 53 views
4

好,我已搜查SO和谷歌,但还没有真正找到一个明确的答案,以便把它扔在那里的SO社区。从MSSQL数据库表中获取最近的经度和纬度?

基本上我有一个关于特定兴趣点的经度和纬度表,sql查询会知道你当前位于哪个位置(哪个位置是表中的那个位置,作为参数传入),因此它那么需要计算并返回最接近经纬度的一行到传入的一行。

我需要这一切都在MSSQL(2012 /存储过程)而不是在调用应用程序(这是.NET),因为我听说SQL处理此类查询通常比.NET更快?

编辑:

我已经找到了STDistance功能赋予英里的诸如位置之间的数字:

DECLARE @NWI geography, @EDI geography 
SET @NWI = geography::Point(52.675833,1.282778,4326) 
SET @EDI = geography::Point(55.95,-3.3725,4326) 
SELECT @NWI.STDistance(@EDI)/1000 

但是我不希望有通过所有的纬度/迭代当然,这对表演会很糟糕吗?

我还试图转换在下面评论链接之一(这是MYSQL不MSSQL)但是我得到一个错误的一个例子所指出的,代码如下:

DECLARE @orig_lat decimal(6,2), @orig_long decimal(6,2), @bounding_distance int 
set @orig_lat=52.056736; 
set @orig_long=1.14822; 
set @bounding_distance=1; 

SELECT *,((ACOS(SIN(@orig_lat * PI()/180) * SIN('lat' * PI()/180) + COS(@orig_lat * PI()/180) * COS('lat' * PI()/180) * COS((@orig_long - 'lon') * PI()/180)) * 180/PI()) * 60 * 1.1515) AS 'distance' 
FROM [DB1].[dbo].[LatLons] 
WHERE 
(
    'lat' BETWEEN (@orig_lat - @bounding_distance) AND (@orig_lat + @bounding_distance) 
    AND 'lon' BETWEEN (@orig_long - @bounding_distance) AND (@orig_long + @bounding_distance) 
) 
ORDER BY 'distance' ASC 

误差收到的是:

Msg 8114,Level 16,State 5,Line 6将数据类型varchar 转换为数字时出错。

任何人都能解决上述问题或想出更好的解决方案吗?

+1

这可能是你在找什么http://stackoverflow.com/questions/592209/find-closest-numeric-value-in-database – makciook

+2

看起来像你的答案在这里http://stackoverflow.com/questions/5826430/great-circle-distance-formula-t-sql – jeffo

+0

如果建议的主题不能帮助你,请发布你的样本数据。 –

回答

4

我写了一篇博客在几年前,解释如何能在不使用空间数据类型来完成。由于看起来好像你有一张经度/纬度值表,这个博客可能会有很大的帮助。

SQL Server Zipcode Latitude Longitude Proximity Search

+0

@G马斯特罗斯你的博客文章只是天才!只需稍微调整一下,我就可以得到它对抗我的数据,我必须承认它的性能是传奇的,我衷心感谢帮助解决我的问题:-) – Apqu

0

由于这是SQL Server,只需在表格的纬度/经度列上放置一个空间索引,然后使用WHERE子句中的.STDistance()函数对其进行查询。

本文从微软文档解释了如何做到这一点:http://msdn.microsoft.com/en-us/library/ff929109.aspx。第二部分“最近邻查询..”似乎特别相关。

2

在我的表我有5个字段:姓名],[定时],[说明],[Lattitude],[经度]。这里用户可以传递他/她想要结果的当前位置和距离。

declare @latitude float, @longitude float, @distance float 
select @latitude = 28.6493, @longitude = 77.2217 , @distance = 5 
;with RestroomLocationsWithDistance as 
    (
     select 
     [Name] ,[Timings]  ,[Description], 
     (3959 * acos(cos(radians(@latitude)) * cos(radians([Lattitude])) * cos(radians([Longitude]) 
     - radians(@longitude)) + sin(radians(@latitude)) * sin(radians([Lattitude])))) As Distance    
     FROM [dbo].[Locations] 
    ) 
    select 
    [Name] ,[Timings]  ,[Description], Distance   
    from RestroomLocationsWithDistance 
    where Distance <= @distance 
+0

是以英里或公里为单位的距离? –

7

我们来看一个在SQL Server 2008(及更高版本)中使用STDistance函数的简单示例。

我要告诉SQL服务器,我在伦敦是的,我想看看有多远我的每个办公室都是。下面是我想要的SQL Server的结果给我:

Offices

首先,我们需要一些样本数据。我们将创建一个包含微软办公室几个位置的表格,我们将其012纬度值的经度&存储在geography字段中。

CREATE TABLE [Offices] (
    [Office_Id] [int] IDENTITY(1, 1) NOT NULL, 
    [Office_Name] [nvarchar](200) NOT NULL, 
    [Office_Location] [geography] NOT NULL, 
    [Update_By] nvarchar(30) NULL, 
    [Update_Time] [datetime] 
) ON [PRIMARY] 

GO 

INSERT INTO [dbo].[Offices] VALUES ('Microsoft Zurich', 'POINT(8.590847 47.408860)', 'mike', GetDate()) 
INSERT INTO [dbo].[Offices] VALUES ('Microsoft San Francisco', 'POINT(-122.403697 37.792062)', 'mike', GetDate()) 
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Paris', 'POINT(2.265509 48.833946)', 'mike', GetDate()) 
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Sydney', 'POINT(151.138378 -33.796572)', 'mike', GetDate()) 
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Dubai', 'POINT(55.286282 25.228850)', 'mike', GetDate()) 

现在,假设我们在伦敦。下面是如何使一个geography值了伦敦的经度纬度&值:

DECLARE 
    @latitude numeric(12, 7), 
    @longitude numeric(12, 7) 

SET @latitude = 51.507351 
SET @longitude = -0.127758 

DECLARE @g geography = 'POINT(' + cast(@longitude as nvarchar) + ' ' + cast(@latitude as nvarchar) + ')'; 

最后,让我们看看有多远我们每个办事处是。

SELECT [Office_Name], 
     cast([Office_Location].STDistance(@g)/1609.344 as numeric(10, 1)) as 'Distance (in miles)' 
FROM [Offices] 
ORDER BY 2 ASC 

这给了我们期待的结果。

Results

很明显,你可以穿过的一个TOP(1)如果你只是想看看最接近办公室。

Top1results

酷,哎?

只有一个障碍。即使您在该数据库字段中添加了SPATIAL INDEX,当您有很多geography积分进行比较时,性能也不是很好。

我测试了一个点对330,000 geography点的表。使用这里显示的代码,它发现最接近的点在8秒

当我修改表来存储经度和纬度值,并且使用了[dbo].[fnCalcDistanceMiles]功能from this StackOverflow article,它发现的最近点约3秒

但是......

所有样品的“两点之间的距离”我发现在互联网上或者是用在SQL Server STDistance功能,或涉及(CPU密集型)COS,罪恶和棕褐色的数学公式功能。

更快的解决方案是及时回到高中,记住毕达哥拉斯如何计算两点之间的距离。

假设我们想知道伦敦和巴黎之间的距离。

enter image description here

这是我的SQL Server的功能:

CREATE FUNCTION [dbo].[uf_CalculateDistance] (@Lat1 decimal(8,4), @Long1 decimal(8,4), @Lat2 decimal(8,4), @Long2 decimal(8,4)) 
RETURNS decimal (8,4) AS 
BEGIN 
    DECLARE @d decimal(28,10) 

    SET @d = sqrt(square(abs(@[email protected])) + square(abs(@[email protected]))) 

    RETURN @d 
END 

现在,请记住这个函数不返回英里的价值,公里等..它只是比较经度纬度&值。而毕达哥拉斯是用于二维,而不是比较圆形星球上的点!

但是,在我的测试中,它发现1秒内的最近点,并且产生了与使用SQL Server的STDistance函数相同的结果。

因此,请随意使用此功能来比较相对距离,但如果您需要实际距离本身,请勿使用此功能。

希望这一切都有所帮助。

+1

在你的“毕达哥拉斯”函数中,使用“abs”是多余的。 'square(-3)'产生9 –

+1

如果你只想找到最近的,你甚至不需要sqrt –

0

在这里,我怎么用麦克的功能上面:

SELECT TOP 1 [State], [City], [AddressID], sqrt(square(abs([email protected])) + square(abs([email protected]))) as Distance 
    FROM [LocationAddresses] la  
    ORDER BY Distance