sql距离查询,多多指教

139 阅读1分钟

ROUND(
6378.138 * 2 * ASIN(
SQRT(
POW(
SIN(
(
用户纬度 * PI() / 180 - 纬度字段名* PI() / 180
) / 2
),
2
) + COS(用户纬度 * PI() / 180) * COS(纬度字段名 * PI() / 180) * POW(
SIN(
(
用户经度 * PI() / 180 - 经度字段名 * PI() / 180
) / 2
),
2
)
)
) * 1000
) AS juli

 创建函数:
    drop function if exists calc_rice;
    create function calc_rice(lng1 varchar(20), lat1 varchar(20), lng2 varchar(20), lat2 varchar(20)) returns int  
    begin 
      return ROUND(6378.138 * 2 * ASIN(SQRT(
           POW(SIN((  lat1  * PI() / 180 - lat2  * PI() / 180 ) / 2), 2) + 
           COS(  lat1  * PI() / 180) * COS(lat2 * PI() / 180) * 
           POW(SIN((  lng1  * PI() / 180 - lng2 * PI() /180) / 2), 2)
         )) * 1000 ); 
    end ;
注释:
(当前经度, 当前纬度, 需要比对的经度,需要比对的纬度) 
   测试 
    select calc_rice(127, 33, 127, 34) as rice 
   
   如果创建时报错:
    This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its de
   请在root账号下执行:
    set global log_bin_trust_function_creators=TRUE;
SELECT
    id,
		name,
    lat,
    lng,

    ROUND(
        6378.138 * 2 * ASIN(
            SQRT(
                POW(
                    SIN(
                        (
                            40.042307 * PI() / 180 - lat * PI() / 180
                        ) / 2
                    ),
                    2
                ) + COS(40.042307 * PI() / 180) * COS(lat * PI() / 180) * POW(
                    SIN(
                        (
                            116.317205 * PI() / 180 -   lng * PI() / 180
                        ) / 2
                    ),
                    2
                )
            )
        ) * 1000
    ) AS juli
FROM
fa_shop
ORDER BY
    juli DESC
$sql =" SELECT   id, name,  lat,  lng,  ";
$sql .=latlngfield("40.042307", "116.317205") ;
$sql .= " FROM fa_shop ORDER BY juli DESC";
//距离排序 字段生成
  function latlngfield($lat, $lng,$latfield="lat", $lngfield="lng", $returnfield="juli") {
            $sql=" ROUND( 6378.138 * 2 * ASIN(  SQRT(  POW(  SIN(  ( ";
            $sql.= $lat." * PI() / 180 - ".$latfield." * PI() / 180  ) / 2 ), 2  ) + COS( ";
            $sql.= $lat." * PI() / 180) * COS( ".$latfield." * PI() / 180) * POW(  SIN(   (   ";
            $sql.= $lng." * PI() / 180 -  ". $lngfield." * PI() / 180 ) / 2  ), 2  ) ) ) * 1000 ) AS   " .$returnfield.""; 
            return $sql;
	}
 

tp用法
//距离排序 字段生成

  function latlngfield($lat, $lng,$latfield="lat", $lngfield="lng", $returnfield="juli") {
            $sql=" ROUND( 6378.138 * 2 * ASIN(  SQRT(  POW(  SIN(  ( ";
            $sql.= $lat." * PI() / 180 - ".$latfield." * PI() / 180  ) / 2 ), 2  ) + COS( ";
            $sql.= $lat." * PI() / 180) * COS( ".$latfield." * PI() / 180) * POW(  SIN(   (   ";
            $sql.= $lng." * PI() / 180 -  ". $lngfield." * PI() / 180 ) / 2  ), 2  ) ) ) * 1000 ) AS   " .$returnfield.""; 
            return $sql;
	}
Db::name("user")
->field("id, name,  lat,  lng,".latlngfield("40.042307", "116.317205"))
->where(["juli","<","1000000"])
->order("juli desc")
->select();

php算距离

/**
 * 根据经纬度算距离,返回结果单位是公里,先纬度,后经度
 * @param $lat1
 * @param $lng1
 * @param $lat2
 * @param $lng2
 * @return float|int
 */
public function GetDistance($lat1, $lng1, $lat2, $lng2)
{
    $EARTH_RADIUS = 6378.137;

    $radLat1 = $this->rad($lat1);
    $radLat2 = $this->rad($lat2);
    $a = $radLat1 - $radLat2;
    $b = $this->rad($lng1) - $this->rad($lng2);
    $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2)));
    $s = $s * $EARTH_RADIUS;
    $s = round($s * 10000) / 10000;

    return $s;
}

private function rad($d)
{
    return $d * M_PI / 180.0;
}

在这里插入图片描述