在SQLite中查询获取基于Radius的logging?

我有这个查询,在MySQL中工作正常

SELECT ((ACOS(SIN(12.345 * PI() / 180) * SIN(lat * PI() / 180) + COS(12.345 * PI() / 180) * COS(lat * PI() / 180) * COS((67.89 - lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515 * 1.609344) AS distance, poi.* FROM poi WHERE lang='eng' HAVING distance<='30' 

距离以公里为单位,input为lat=12.345lon=67.89

SQLite是3,我不能像在Android上一样运行自定义函数。 我也没有acos()等等,因为这不是标准的SQLite的一部分。

SQLite中的上述查询将如何?

您可以创build4个新列,分别是latlon 。 由于cos(a+b) = cos a cos b - sin a sin b ,在执行查询之前可以在程序中计算SIN(12.345 * PI() / 180)和cos的其他外观SIN(12.345 * PI() / 180)距离“expression式P * SIN_LAT + Q * COS_LAT + ...为SQLite3可以处理的formsP * SIN_LAT + Q * COS_LAT + ...

顺便说一句,另请参阅Android上的Sqlite:如何创build一个SQLite远程数据库函数 – 在应用程序中使用拉特,长距离计算 。

这是Java中的一个实现,用于在Android设备上构build基于位置的查询。 这个想法来自KennyTM(参见接受的回答),并且在表格中增加了4列来存储经度和纬度的正弦和余弦值。

以下是在插入时为“商店”表格准备数据的代码:

 public static void injectLocationValues(ContentValues values, double latitude, double longitude) { values.put(LocationColumns.LATITUDE, latitude); values.put(LocationColumns.LONGITUDE, longitude); values.put(LocationColumns.COSLAT, Math.cos(MathUtil.deg2rad(latitude))); values.put(LocationColumns.SINLAT, Math.sin(MathUtil.deg2rad(latitude))); values.put(LocationColumns.COSLNG, Math.cos(MathUtil.deg2rad(longitude))); values.put(LocationColumns.SINLNG, Math.sin(MathUtil.deg2rad(longitude))); } public static double deg2rad(double deg) { return (deg * Math.PI / 180.0); } 

然后,您可以使用以下函数来构build投影:

 /** * Build query based on distance using spherical law of cosinus * * d = acos(sin(lat1).sin(lat2)+cos(lat1).cos(lat2).cos(long2−long1)).R * where R=6371 and latitudes and longitudes expressed in radians * * In Sqlite we do not have access to acos() sin() and lat() functions. * Knowing that cos(AB) = cos(A).cos(B) + sin(A).sin(B) * We can determine a distance stub as: * d = sin(lat1).sin(lat2)+cos(lat1).cos(lat2).(cos(long2).cos(long1)+sin(long2).sin(long1)) * * First comparison point being fixed, sin(lat1) cos(lat1) sin(long1) and cos(long1) * can be replaced by constants. * * Location aware table must therefore have the following columns to build the equation: * sinlat => sin(radians(lat)) * coslat => cos(radians(lat)) * coslng => cos(radians(lng)) * sinlng => sin(radians(lng)) * * Function will return a real between -1 and 1 which can be used to order the query. * Distance in km is after expressed from R.acos(result) * * @param latitude, latitude of search * @param longitude, longitude of search * @return selection query to compute the distance */ public static String buildDistanceQuery(double latitude, double longitude) { final double coslat = Math.cos(MathUtil.deg2rad(latitude)); final double sinlat = Math.sin(MathUtil.deg2rad(latitude)); final double coslng = Math.cos(MathUtil.deg2rad(longitude)); final double sinlng = Math.sin(MathUtil.deg2rad(longitude)); //@formatter:off return "(" + coslat + "*" + LocationColumns.COSLAT + "*(" + LocationColumns.COSLNG + "*" + coslng + "+" + LocationColumns.SINLNG + "*" + sinlng + ")+" + sinlat + "*" + LocationColumns.SINLAT + ")"; //@formatter:on } 

它将注入一个响应列,其中需要应用以下公式进行公里转换的距离:

 public static double convertPartialDistanceToKm(double result) { return Math.acos(result) * 6371; } 

如果要使用部分距离来sorting查询,则需要命令DESC而不是ASC。

如果在使用sqlite3 for ios的时候遇到同样的问题,在用这个公式玩这个游戏之后,不用使用函数(伪代码)就可以做到这一点:

  1. 为您存储在数据库中的每个项目预先计算这些值(并存储它们):

     cos_lat = cos(lat * PI / 180) sin_lat = sin(lat * PI / 180) cos_lng = cos(lng * PI / 180) sin_lng = sin(lng * PI / 180) 
  2. 在search时间预先计算这些值(对于给定位置cur_lat,cur_lng)

     CUR_cos_lat = cos(cur_lat * PI / 180) CUR_sin_lat = sin(cur_lat * PI / 180) CUR_cos_lng = cos(cur_lng * PI / 180) CUR_sin_lng = sin(cur_lng * PI / 180) cos_allowed_distance = cos(2.0 / 6371) # This is 2km 
  3. 你的SQL查询将如下所示(用你刚刚计算的值replaceCUR_ *)

    SELECT * FROM where where CUR_sin_lat * sin_lat + CUR_cos_lat * cos_lat *(cos_lng * CUR_cos_lng + sin_lng * CUR_sin_lng)> cos_allowed_distance;