我正在开发一个位置应用程序,我需要从我的Mysql Location表中获取所有位置,它们之间的距离为5km。
对于Ex位置表,下面有条目:
id Latitude Longitude
1 22.7499180 75.8950577
2 22.7498474 75.8950653
3 22.7498035 75.8950424
4 22.7497787 75.8950729
5 22.7498245 75.8950806
6 22.7497902 75.8950272
7 22.7497864 75.8950424
8 22.7497768 75.8950500
9 22.7497864 75.8950577
10 22.7497921 75.8950653
11 22.7497597 75.8950653
12 22.7498283 75.8950653
13 22.7497978 75.8950577
所以从上面的表格中我需要获取类似这样的结果
id Latitude Longitude Distance (>=5Km)
1 22.7499180 75.8950577 --
4 22.7497787 75.8950729 6km (From lat long of id 1)
8 22.7497768 75.8950500 8km (From lat long of id 4)
11 22.7497597 75.8950653 6km (From lat long of id 8)
13 22.7497978 75.8950577 10km (From lat long of id 11)
我搜索了很多以获得这样的结果,但我只是根据一些固定的纬度/长度或固定半径得到结果。如果可能,请帮助Mysql查询。
修改(来自OP的评论)
我需要的是计算距离上一个选定值的距离......对于Ex。从记录1开始。将距离1与记录2进行比较,它是<1。 5km,与记录3相比也<5。 5km,与4相比,距离> 5km。 5km所以我们将它保持在列表中,而下一个记录将与记录4进行比较。因此4的距离将与5进行比较,如果记录5的距离> 5。距离4下一个比较5km,记录5作为参考。
答案 0 :(得分:6)
没有存储过程,只是纯粹的肆无忌惮的sql荣耀:
SET @prevLong=-1.0000;
SET @prevLat=-1.0000;
SET @currDist=1.0000;
select id, diff from (
select id,
@prevLat prev_lat,
@currDist:= 6371 * 2 * (atan2(sqrt(sin(radians(@prevLat - lat)/2)
* sin(radians(@prevLat - lat)/2)
+ cos(radians(lat))
* cos(radians(@prevLat))
* sin(radians(@prevLong - longi)/2)
* sin(radians(@prevLong - longi)/2))
,sqrt(1-(sin(radians(@prevLat - lat)/2)
* sin(radians(@prevLat - lat)/2)
+ cos(radians(lat))
* cos(radians(@prevLat))
* sin(radians(@prevLong
- longi)/2)
* sin(radians(@prevLong - longi)/2))))) diff,
@prevLong prevLong,
case when @currdist > 5 then @prevLat:=lat else null end curr_lat,
case when @currDist > 5 then @prevLong:= longi else null end curr_long
from latLong
order by id asc
) a where diff > 5
SQLFiddle证明魔法是真实的: http://sqlfiddle.com/#!9/7e4fe/19
修改强> 在Codeigniter中,您可以使用如下变量:
$this->db->query("SET @prevLong=-1.0000");
$this->db->query("SET @prevLat=-1.0000");
$this->db->query("SET @prevDist=-1.0000");
然后正常发出您的查询
$query= $this->db->query("SELECT ...");
答案 1 :(得分:2)
所以你需要计算Lat Lon的距离,然后检查结果是否大于5km。您的样本数据存在问题,即计算的距离在米范围内,因此您无法获得任何结果。我想你还有几个地方可以在你的桌子上查看。
试
SELECT
a.id, a.Latitude, a.Longitude, CONCAT(a.ID,"-",b.ID) as 'FromTo',
6371 * acos(
cos(radians( b.Latitude ))
* cos(radians( a.Latitude ))
* cos(radians( b.Longitude ) - radians( a.Longitude ))
+ sin(radians( b.Latitude ))
* sin(radians( a.Latitude ))) as distance
FROM new_table a INNER JOIN new_table b ON a.id <> b.id
HAVING distance >= 0.001
ORDER BY id, distance;
我将having子句设置为大于一米HAVING distance >= 0.001
。如果你想检查公里相应调整!
修改强>
这可能不是你可能需要稍微调整一下的解决方案,但程序看起来像
DELIMITER $$
CREATE PROCEDURE `calcDistWithin`(IN dist double)
BEGIN
declare maxTempID int;
declare maxTblID int;
declare breakLoop boolean;
SET breakLoop = FALSE;
DROP TEMPORARY TABLE IF EXISTS tmp;
CREATE TEMPORARY TABLE tmp (ID int, Latitude double, Longitude double, distance double, toID varchar(10));
DROP TEMPORARY TABLE IF EXISTS tmpOUT;
CREATE TEMPORARY TABLE tmpOUT (ID int, Latitude double, Longitude double, distance double, toID varchar(10));
INSERT INTO tmp select ID, Latitude, Longitude, 0, "---" from new_table limit 1;
INSERT INTO tmpOUT select ID, Latitude, Longitude, 0, "---" from new_table limit 1;
SELECT ID INTO maxTblID FROM new_table ORDER BY ID DESC LIMIT 1;
SELECT ID into maxTempID FROM tmp ORDER BY ID DESC LIMIT 1;
WHILE breakLoop = FALSE DO
IF EXISTS (SELECT
6371 * acos(
cos(radians( b.Latitude ))
* cos(radians( a.Latitude ))
* cos(radians( b.Longitude ) - radians( a.Longitude ))
+ sin(radians( b.Latitude ))
* sin(radians( a.Latitude ))) as distance
FROM tmp a INNER JOIN new_table b
WHERE a.ID < b.ID AND a.ID = maxTempID
HAVING distance >= dist
LIMIT 1) THEN
INSERT INTO tmpOUT SELECT
b.ID, b.Latitude, b.Longitude,
6371 * acos(
cos(radians( b.Latitude ))
* cos(radians( a.Latitude ))
* cos(radians( b.Longitude ) - radians( a.Longitude ))
+ sin(radians( b.Latitude ))
* sin(radians( a.Latitude ))) as distance,
a.ID
FROM tmp a INNER JOIN new_table b
WHERE a.ID < b.ID AND a.ID = maxTempID
HAVING distance >= dist
ORDER BY a.ID, b.ID, distance
LIMIT 1;
INSERT INTO tmp SELECT ID, Latitude, Longitude, distance, toID FROM tmpOUT ORDER BY ID DESC LIMIT 1;
SELECT ID into maxTempID FROM tmpOUT order by ID DESC LIMIT 1;
ELSE
SET breakLoop = TRUE;
END IF;
END WHILE;
SELECT * FROM tmpOUT;
END$$
DELIMITER ;
调用它只需使用
CALL calcDistWithin(5.00)
答案 2 :(得分:0)
我不确定你是否想要一个纯粹的SQL解决方案。 我只能用其他语言提供解决方案。 我假设使用id来确定最近的节点。
List locat= new List();
last = getTheLastRecord();
locat.add(last);
count = getTheCountOfRecord();
for(int i=1;i<count;i++){//i = 1 because last record already read.
Record r = getRecord(i);
if(compareDistance(r,last)>5000){
locat.add(r);
last = r;
}
}
//最后,locat列表将包含您想要的每个位置。