新项目需求:
结合百度地图,在地图中指定一个地点,获取此地点周围1km范围内所有数据库中存的单位的地点和信息标记在地图上。于是初写了一把oracle
的存储过程,纯靠摸索写的。
后台需要的函数如下:
首先,计算圆弧函数
CREATE OR REPLACE FUNCTION RAD(d number) RETURN NUMBER
is
PI number :=3.141592625;
begin
return d* PI/180.0;
end ;
然后,计算距离函数
CREATE OR REPLACE FUNCTION GetDistance(lat1 number,
lng1 number,
lat2 number,
lng2 number) RETURN NUMBER is
earth_padius number := 6378.137;
radLat1 number := rad(lat1);
radLat2 number := rad(lat2);
a number := radLat1 - radLat2;
b number := rad(lng1) - rad(lng2);
s number := 0;
begin
s := 2 *
Asin(Sqrt(power(sin(a / 2), 2) +
cos(radLat1) * cos(radLat2) * power(sin(b / 2), 2)));
s := s * earth_padius;
s := Round(s * 10000) / 10000;
return s;
end;
接下来是我自己写的存储过程:
CREATE OR REPLACE PROCEDURE distance_maintunit(p_cur out sys_refcursor, center_lat in number , center_lng in number)
IS
v_muids VARCHAR(200);
v_distance NUMERIC(9,6);
BEGIN
FOR L_RECORD IN (select * from M_MAINTENACEUNIT)
LOOP
SELECT GetDistance(L_RECORD.Lat,L_RECORD.Longitude,center_lat,center_lng) INTO v_distance FROM dual;
/*dbms_output.put_line('distance:' || v_distance);*/
IF (v_distance <=1)
THEN
v_muids:= v_muids || L_RECORD.muid || ',';
END IF;
END LOOP;
v_muids:= v_muids || '-1';
dbms_output.put_line(v_muids);
open p_cur for 'select * from m_maintenaceunit where muid in ('||v_muids||')';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
dbms_output.put_line(SQLERRM);
END;
由于使用mybatis
,所以service
调用如下:
@Override
public List<MaintunitDto> getMaitunitByProcedures(Double lat, Double lng) {
Map<String ,Object> map=new HashMap<String, Object>();
map.put("lng", lng);
map.put("lat", lat);
try {
geoDao.getMaitunitByProcedures(map);
}catch(UncategorizedSQLException e) {
// System.out.println(e);
e.printStackTrace();
}
@SuppressWarnings("unchecked")
List<MaintunitDto> siteList=(List<MaintunitDto>)map.get("maintunits");
return siteList;
}
这里跟我之前转载的那篇关于oracle
存储过程的文章有关联(如何调用一个返回集合的存储过程)
mapper.xml
中的调用:
<select id="getMaitunitByProcedures" statementType="CALLABLE" parameterType="java.util.Map">
select>
<resultMap type="com.cseds.geo.dto.MaintunitDto" id="MAINTUNIT_MAP">
resultMap>
dao
中调用:
public List getMaintUnitList(@Param("lng") Double lng, @Param("lat") Double lat);
由于第一次写oracle
存储过程,代码只是实现了功能,有待改进。
在 Oracle 中根据经纬度计算两地之间的距离
获得弧度的函数:
CREATE OR REPLACE FUNCTION Radian(d number) RETURN NUMBER
is
PI number :=3.141592625;
begin
return d* PI/180.0;
end ;
测试一下这个函数:
select Radian(360) from dual;
根据经纬度计算距离的函数:
CREATE OR REPLACE FUNCTION GetDistance(lat1 number,
lng1 number,
lat2 number,
lng2 number) RETURN NUMBER is
earth_padius number := 6378.137;
radLat1 number := Radian(lat1);
radLat2 number := Radian(lat2);
a number := radLat1 - radLat2;
b number := Radian(lng1) - Radian(lng2);
s number := 0;
begin
s := 2 *
Asin(Sqrt(power(sin(a / 2), 2) +
cos(radLat1) * cos(radLat2) * power(sin(b / 2), 2)));
s := s * earth_padius;
s := Round(s * 10000) / 10000;
return s;
end;
示例,根据城市名计算距离:
东方明珠塔的经纬度是:121.506656,31.245087
陆家嘴地铁站的经纬度是:121.508883,31.243481
SQL> select GetDistance('121.506656','31.245087','121.508883','31.243481') from dual;
输出结果是 0.2649 千米
这里用到的算法和地球半径等数据均来自网络,此文只作整理记录。
地球半径值采用赤道半径 6378137.0
米,这是1980
年的国际标准数据。
下面是在数据库中写的自定义函数,传入两个经纬度点的数据,共4个参数,返回以米为单位的两点之间的距离
CREATE FUNCTION [f_GetDistance]
(
@GPSLng DECIMAL(12,6),
@GPSLat DECIMAL(12,6),
@Lng DECIMAL(12,6),
@Lat DECIMAL(12,6)
)
RETURNS DECIMAL(12,4)
AS
BEGIN
DECLARE @result DECIMAL(12,4)
SELECT @result = 6378137.0*ACOS(SIN(@GPSLat/180*PI())*SIN(@Lat/180*PI())+COS(@GPSLat/180*PI())*COS(@Lat/180*PI())*COS((@GPSLng-@Lng)/180*PI()))
RETURN @result
END
GO