獲取資料庫中到指定經緯度距離的座標

風靈使發表於2018-04-20

oracle儲存過程

新專案需求:

結合百度地圖,在地圖中指定一個地點,獲取此地點周圍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">
    <![CDATA[ 
    {call distance_maintunit(

    #{maintunits,jdbcType=CURSOR,mode=OUT,resultMap=MAINTUNIT_MAP,javaType=ResultSet},
    #{lat,jdbcType=DOUBLE,mode=IN},
    #{lng,jdbcType=DOUBLE,mode=IN}

    )}
    ]]> 
</select>

<resultMap type="com.cseds.geo.dto.MaintunitDto" id="MAINTUNIT_MAP">
</resultMap>

dao中呼叫:

public List<MaintunitDto> getMaintUnitList(@Param("lng") Double lng, @Param("lat") Double lat);

由於第一次寫oracle儲存過程,程式碼只是實現了功能,有待改進。


在 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 千米


sql server 計算兩個經緯度點之間的距離

這裡用到的演算法和地球半徑等資料均來自網路,此文只作整理記錄。

地球半徑值採用赤道半徑 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  

相關文章