zl程序教程

您现在的位置是:首页 >  后端

当前栏目

SQL Server根据地图坐标经纬度计算距离

server计算SQL 根据 地图 距离 坐标 经纬度
2023-09-11 14:14:50 时间

实战1-亲测,返回结果是米(m)

如果嫌麻烦直接跳转至:“参考方案一”

注意:该方法仅支持 SQL Server 2008 和该版本以上的数据库 

1、准备-工具

百度坐标拾取器:

http://api.map.baidu.com/lbsapi/getpoint/index.html

百度地图:https://map.baidu.com/

2、准备-SQL语句,新增一张表

USE [DBTase]
GO
/****** Object:  Table [dbo].[distance_lat_lng]    Script Date: 2021/11/4 16:16:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[distance_lat_lng](
	[id] [int] IDENTITY(1,1) NOT NULL,
	[Name] [nchar](50) NOT NULL,
	[lng] [real] NOT NULL,
	[lat] [real] NOT NULL,
 CONSTRAINT [PK_distance_lat_lng] PRIMARY KEY CLUSTERED 
(
	[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[distance_lat_lng] ON 

GO
INSERT [dbo].[distance_lat_lng] ([id], [Name], [lng], [lat]) VALUES (1, N'河南青少年中心', 113.694893, 34.78782)
GO
INSERT [dbo].[distance_lat_lng] ([id], [Name], [lng], [lat]) VALUES (2, N'财源大厦', 113.693436, 34.78596)
GO
INSERT [dbo].[distance_lat_lng] ([id], [Name], [lng], [lat]) VALUES (5, N'我的位置【中原油气】公司宿舍', 113.695381, 34.7867737)
GO
SET IDENTITY_INSERT [dbo].[distance_lat_lng] OFF
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'经度' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'distance_lat_lng', @level2type=N'COLUMN',@level2name=N'lng'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'纬度' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'distance_lat_lng', @level2type=N'COLUMN',@level2name=N'lat'
GO

3、基础测试:

DECLARE @g geography;
DECLARE @h geography;
SET @g = geography::STGeomFromText('POINT(113.694893 34.78782)', 4326);
SET @h = geography::STGeomFromText('POINT(113.693436 34.78596)', 4326);
SELECT @g.STDistance(@h);

结果

245.681793435016

根据下面“图一”和“图二”的测距结果,和sql结果对比,得出的距离是米,距离范围相差不多

图一

图二

4、创建一个“标量函数”


CREATE FUNCTION fun_Get_distance_lat_lng_1
(
 @destination_lng varchar(30),
 @destination_lat varchar(30),
 @myLocation_lng varchar(30),
 @myLocation_lat varchar(30)
)
RETURNS varchar(30) AS 

-- @destination_lng 目标经度
-- @destination_lat 目标纬度
-- @myLocation_lng  我的经度
-- @myLocation_lat  我的纬度

BEGIN
	declare @distance varchar(30);--返回值
	declare @destination geography,@myLocation geography;
	--@destination 目标位置
	--@myLocation 我的位置
	--@distance 距离
	SET @destination = geography::STGeomFromText('POINT(' +@destination_lng+ ' ' + @destination_lat +')', 4326);
	SET @myLocation = geography::STGeomFromText('POINT(' + @myLocation_lng+ ' ' + @myLocation_lat+')', 4326);
	SET @distance=cast(@destination.STDistance(@myLocation) as varchar(30));
 
	return @distance
END

不知道标量函数的可以看下面的文章 

sql server 中的表值函数和标量函数 - cplvfx - 博客园sql server 中的表值函数和标量函数https://www.cnblogs.com/cplvfx/articles/15508241.html#4963500

 这个就是刚才新建的“标量函数”

5、调用“标量函数”

select dbo.fun_Get_distance_lat_lng_1('113.694893','34.78782','113.693436','34.78596')

 结果

245.682

 根据“图一”和“图二”的测距结果,和sql结果对比,得出的距离是米,距离范围相差不多

 6、根据刚才创建的表 批量算距离

select * from [dbo].[distance_lat_lng]
--根据刚才创建的表 批量算距离
declare @myLocation_lng varchar(30), @myLocation_lat varchar(30);
set @myLocation_lng='113.695381';
set @myLocation_lat='34.7867737';
-- @myLocation_lng  我的经度
-- @myLocation_lat  我的纬度

select
 dis.id,
 dis.lng,
 dis.lat,
 dis.Name,
 dbo.fun_Get_distance_lat_lng_1(cast(dis.lng as varchar(30)),cast(dis.lat as varchar(30)),@myLocation_lng,@myLocation_lat) as distance
 from [dbo].[distance_lat_lng] as dis

数据存储的数据

idNamelnglat
1河南青少年中心                                           113.69489334.78782
2财源大厦                                              113.69343634.78596
5我的位置【中原油气】公司宿舍                                    113.69538134.7867737

执行结果 

idlnglatNamedistance(距离)
1113.69489334.78782河南青少年中心                                           124.37
2113.69343634.78596财源大厦                                              199.595
5113.69538134.7867737我的位置【中原油气】公司宿舍                                    0

 根据“图三”和“图四”的测距结果,和sql结果对比,得出的距离是米,距离范围相差不多

图三

图四

7、跟坐标距离小于5公里的数据

select
 dis.id,
 dis.lng,
 dis.lat,
 dis.Name,
 dbo.fun_Get_distance_lat_lng_1(cast(dis.lng as varchar(30)),cast(dis.lat as varchar(30)),@myLocation_lng,@myLocation_lat) as distance
 from [dbo].[distance_lat_lng] as dis  WHERE dbo.fnGetDistance(cast(dis.lat as REAL),cast(dis.lng as REAL),@myLocation_lat,@myLocation_lng) < 5000

 结果

idlnglatNamedistance
1113.69489334.78782河南青少年中心                                           0.124602102
2113.69343634.78596财源大厦                                              0.199557602
5113.69538134.7867737我的位置【中原油气】公司宿舍                                    0

实战2-亲测-返回结果是公里(km)

参考:https://www.cnblogs.com/smartsmile/p/6234120.html

1、创建一个“标量函数”

CREATE FUNCTION [dbo].[fnGetDistance](@LatBegin REAL, @LngBegin REAL, @LatEnd REAL, @LngEnd REAL) RETURNS FLOAT
  AS
BEGIN
  --距离(千米)
  DECLARE @Distance REAL
  DECLARE @EARTH_RADIUS REAL
  SET @EARTH_RADIUS = 6378.137  
  DECLARE @RadLatBegin REAL,@RadLatEnd REAL,@RadLatDiff REAL,@RadLngDiff REAL
  SET @RadLatBegin = @LatBegin *PI()/180.0  
  SET @RadLatEnd = @LatEnd *PI()/180.0  
  SET @RadLatDiff = @RadLatBegin - @RadLatEnd  
  SET @RadLngDiff = @LngBegin *PI()/180.0 - @LngEnd *PI()/180.0   
  SET @Distance = 2 *ASIN(SQRT(POWER(SIN(@RadLatDiff/2), 2)+COS(@RadLatBegin)*COS(@RadLatEnd)*POWER(SIN(@RadLngDiff/2), 2)))
  SET @Distance = @Distance * @EARTH_RADIUS  
  --SET @Distance = Round(@Distance * 10000) / 10000  
  RETURN @Distance
END 

不知道标量函数的可以看下面的文章 

sql server 中的表值函数和标量函数 - cplvfx - 博客园sql server 中的表值函数和标量函数https://www.cnblogs.com/cplvfx/articles/15508241.html#4963500

 2、根据“实战1”创建的表 批量算距离 -返回结果是公里(km)

--根据刚才创建的表 批量算距离
declare @myLocation_lng REAL, @myLocation_lat REAL;
set @myLocation_lng=113.695381;
set @myLocation_lat=34.7867737;
-- @myLocation_lng  我的经度
-- @myLocation_lat  我的纬度

select
 dis.id,
 dis.lng,
 dis.lat,
 dis.Name,
 dbo.fnGetDistance(cast(dis.lat as REAL),cast(dis.lng as REAL),@myLocation_lat,@myLocation_lng) as distance
 from [dbo].[distance_lat_lng] as dis

结果 

idlnglatNamedistance
1113.69489334.78782河南青少年中心                                           0.124602102
2113.69343634.78596财源大厦                                              0.199557602
5113.69538134.7867737我的位置【中原油气】公司宿舍                                    0

这个结果和“实战1”的结果一模一样,唯一不一样的返回是公里(km)

3、跟坐标距离小于5公里的数据
 

--跟坐标距离小于5公里的数据
SELECT * FROM [distance_lat_lng] as dis WHERE dbo.fnGetDistance(cast(dis.lat as REAL),cast(dis.lng as REAL),@myLocation_lat,@myLocation_lng) < 5

结果 

idNamelnglat
1河南青少年中心                                           113.69489334.78782
2财源大厦                                              113.69343634.78596
5我的位置【中原油气】公司宿舍                                    113.69538134.7867737

参考方案一

参考链接1:https://blog.csdn.net/winnyrain/article/details/51605924

参考链接2:https://my.oschina.net/u/200350/blog/1794111

 注意:该方法仅支持 SQL Server 2008 和该版本以上的数据库 

计算两点距离,4326是空间引用标识符,4326代表GCS-WGS-1984坐标系,是系统默认的坐标系。

地理坐标系空间需要用geography ,平面坐标系空间用geometry,计算距离使用STDistance

DECLARE @g geography;
DECLARE @h geography;
SET @g = geography::STGeomFromText('POINT(104.12765 31.61)', 4326);
SET @h = geography::STGeomFromText('POINT(114.132179 22.547010)', 4326);
SELECT @g.STDistance(@h);

查询某点经纬度距离1000米范围内的记录

SELECT * FROM [GpsData] WHERE 
geography::STGeomFromText('POINT(' + cast([Longitude] as varchar(20)) + ' ' 
+ cast([Latitude] as varchar(20)) +')', 4326).STDistance(
geography::STGeomFromText('POINT(114.132179 22.547010)', 4326))<1000

STDistance也可以计算点到面的最短距离。        

利用的是 geography::STPointFromText()。

第一个参数 POINT() 里面再跟经度、纬度。

第二个参数 4326 代表 GCS-WGS-1984 坐标系。具体本文后面会列出相关链接。

参考:

空间引用标识符

https://technet.microsoft.com/zh-cn/library/bb964707(v=sql.105)

STDistance(geometry 数据类型)
https://msdn.microsoft.com/zh-cn/library/bb933952(v=sql.100).aspx

STDistance的使用及geometry和geography的区别
http://blog.csdn.net/jcx5083761/article/details/46010215

相关阅读


参考方案二

SQL SERVER 根据地图经纬度计算距离函数 - 深南大道 - 博客园前些天客户提出一个这样的要求:一个手机订餐网,查询当前所在位置的5公里范围的酒店,然后客户好去吃饭。 拿到这个请求后,不知道如何下手,静静地想了一下,在酒店的表中增加两个字段,用来存储酒店所在的经度和https://www.cnblogs.com/smartsmile/p/6234120.html

前些天客户提出一个这样的要求:一个手机订餐网,查询当前所在位置的5公里范围的酒店,然后客户好去吃饭。
拿到这个请求后,不知道如何下手,静静地想了一下,在酒店的表中增加两个字段,用来存储酒店所在的经度和纬度,当订餐的时候,要求手机得到当前客户所在的经度和纬度传过来,再与数据库中酒店的经度和纬度计算一下,就查出来。

为了在数据库中查询两点之间的距离,所以这个函数需要在数据库中定义。

我网上找了很久,却没有找到这个函数。最后在CSDN上,一个朋友的帮助下解决了这个问题,非常感谢lordbaby给我提供这个函数,我把这个函数放到这里来,以便帮助更多许要的朋友。

--计算地球上两个坐标点(经度,纬度)之间距离sql函数
--作者:lordbaby
--整理:www.aspbc.com 
CREATE FUNCTION [dbo].[fnGetDistance](@LatBegin REAL, @LngBegin REAL, @LatEnd REAL, @LngEnd REAL) RETURNS FLOAT
  AS
BEGIN
  --距离(千米)
  DECLARE @Distance REAL
  DECLARE @EARTH_RADIUS REAL
  SET @EARTH_RADIUS = 6378.137  
  DECLARE @RadLatBegin REAL,@RadLatEnd REAL,@RadLatDiff REAL,@RadLngDiff REAL
  SET @RadLatBegin = @LatBegin *PI()/180.0  
  SET @RadLatEnd = @LatEnd *PI()/180.0  
  SET @RadLatDiff = @RadLatBegin - @RadLatEnd  
  SET @RadLngDiff = @LngBegin *PI()/180.0 - @LngEnd *PI()/180.0   
  SET @Distance = 2 *ASIN(SQRT(POWER(SIN(@RadLatDiff/2), 2)+COS(@RadLatBegin)*COS(@RadLatEnd)*POWER(SIN(@RadLngDiff/2), 2)))
  SET @Distance = @Distance * @EARTH_RADIUS  
  --SET @Distance = Round(@Distance * 10000) / 10000  
  RETURN @Distance
END

--经度 Longitude 简写Lng,  纬度 Latitude 简写Lat
--跟坐标距离小于5公里的数据
SELECT * FROM 商家表名 WHERE dbo.fnGetDistance(121.4625,31.220937,longitude,latitude) < 5

这里的longitude,latitude分别是酒店的经度和纬度字段,而121.4625,31.220937是手机得到的当前客户所在的经度,后面的5表示5公里范围之内。

JS版本

function toRadians(degree) {
	return degree * Math.PI / 180;
}
function distance(latitude1, longitude1, latitude2, longitude2) {
	// R is the radius of the earth in kilometers
	var R = 6371;
	var deltaLatitude = toRadians(latitude2-latitude1);
	var deltaLongitude = toRadians(longitude2-longitude1);
	latitude1 =toRadians(latitude1);
	latitude2 =toRadians(latitude2);
	var a = Math.sin(deltaLatitude/2) *
	Math.sin(deltaLatitude/2) +
	Math.cos(latitude1) *
	Math.cos(latitude2) *
	Math.sin(deltaLongitude/2) *
	Math.sin(deltaLongitude/2);
	var c = 2 * Math.atan2(Math.sqrt(a),
	Math.sqrt(1-a));
	var d = R * c;
	return d;
}