Apq*_*pqu 6 sql t-sql database sql-server sql-server-2012
好的,我已经搜索了SO和谷歌,但还没有真正找到明确的答案,所以把它扔到那里为SO社区.
基本上我有一个针对特定兴趣点的经度和纬度表,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
Run Code Online (Sandbox Code Playgroud)
但是我不想迭代遍历表中的所有纬度/经度,因为这对于性能来说肯定会很糟糕吗?
我也试过转换下面的一个注释链接中指出的一个例子(这是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
Run Code Online (Sandbox Code Playgroud)
收到的错误是:
消息8114,级别16,状态5,行6错误将数据类型varchar转换为数字.
谁能够解决上述代码或提出更好的解决方案?
让我们看一个STDistance在SQL Server 2008(及更高版本)中使用该函数的简单示例.
我要告诉SQL Server我在伦敦,我希望看到我的办公室离我们有多远.这是我希望SQL Server给我的结果:
首先,我们需要一些样本数据.我们将创建一个包含Microsoft办公室位置的表格,我们将其经度和纬度值存储在一个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())
Run Code Online (Sandbox Code Playgroud)
现在,假设我们在伦敦.以下是如何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) + ')';
Run Code Online (Sandbox Code Playgroud)
最后,让我们看看每个办公室的距离.
SELECT [Office_Name],
cast([Office_Location].STDistance(@g) / 1609.344 as numeric(10, 1)) as 'Distance (in miles)'
FROM [Offices]
ORDER BY 2 ASC
Run Code Online (Sandbox Code Playgroud)
这给了我们希望的结果.
显然,TOP(1)如果你只是想看到最近的办公室,你可以溜进去.
很酷,嘿?
只有一个障碍.当您有很多geography要比较的要点时,即使您在该数据库字段上添加了一个SPATIAL INDEX,性能也不是很好.
我在一张330,000 geography分的桌子上测试了一个点.使用此处显示的代码,它在大约8秒内找到了最近的点.
当我修改我的表以存储经度和纬度值,并使用此StackOverflow文章中的[dbo].[fnCalcDistanceMiles]函数时,它在大约3秒内找到了最近的点.
然而...
我在互联网上找到的所有"两点之间的距离"样本都使用了SQL Server STDistance函数,或者涉及(CPU密集型)cos,sin和tan函数的数学公式.
更快的解决方案是回到高中,并记住毕达哥拉斯如何计算两点之间的距离.
假设我们想知道伦敦和巴黎之间的距离.
这是我的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(@Lat1-@Lat2) + square(@Long1-@Long2))
RETURN @d
END
Run Code Online (Sandbox Code Playgroud)
现在,请记住此函数不会返回以英里,公里等为单位的值...它只是比较经度和纬度值.毕达哥拉斯意在用于2D,而不是比较圆形行星上的点!
但是,在我的测试中,它在1秒内找到了最接近的点,并产生了与使用SQL Server STDistance函数相同的结果.
因此,请随意使用此功能来比较相对距离,但如果您需要实际距离本身,请不要使用此功能.
希望这一切都有帮助.
几年前,我写了一个博客,解释了如何在不使用空间数据类型的情况下完成此操作。由于看起来好像有一张经度/纬度值表,因此该博客可能会有所帮助。
| 归档时间: |
|
| 查看次数: |
10405 次 |
| 最近记录: |