我有以下表格和关系:
Players:
foreign_key to User
Users:
foreign_key to City
Cities:
latitude (float)
longitude (float)
我正在努力让所有与用户相关的教授来自某个城市或近城。
我有这个查询,它给出了具有特定纬度和经度以及给定城市纬度和经度的距离的near_by(20km)城市。在这种情况下latitude = 41.353312 and longitude = 1.976252
:
SELECT cities.*,
6371 *
acos(cos(radians(41.353312)) *
cos(radians(cities.latitude)) *
cos(radians(cities.longitude) - radians(1.976252)) +
sin(radians(41.353312))*sin(radians(cities.latitude)))
AS km_away FROM `cities` GROUP BY km_away ASC HAVING km_away <= 20
我已经尝试过这个查询(无效),我希望它能让我返回给定城市(纬度和经度)附近的相关用户城市的玩家。< / p>
SELECT COUNT(*)
FROM `players`
INNER JOIN `users`
ON `users`.`id` = `players`.`user_id`
INNER JOIN `cities`
ON `cities`.`id` = `users`.`city_id`
WHERE
(
cities.id IN
(SELECT cities.*,
6371 *
acos(cos(radians(41.353312)) *
cos(radians(cities.latitude)) *
cos(radians(cities.longitude) - radians(1.976252)) +
sin(radians(41.353312))*sin(radians(cities.latitude))) AS km_away
FROM `cities`
GROUP BY km_away ASC
HAVING km_away <= 20)
)
我还想:
1 - 按照相关用户城市到指定城市的距离订购玩家。
2 - 获取返回的每条记录的距离(值)。
答案 0 :(得分:2)
我不清楚你要返回什么样的结果集。但是看看你的问题,我想你想要你的子查询(+1!用于“大圆距离”计算离巴塞罗那的距离!)作为行源。
一种方法是将子查询用作“内联视图”,而不是在WHERE子句中引用它。
由于该查询返回cities表中的所有列,因此它基本上可以替换查询中的cities表。
不需要GROUP BY子句。当两个城市与给定的纬度/经度等距时,它仅用于消除结果集中的行。 (我不相信这是你想要的行为,想要这样做并没有错,但这很不寻常。)
SELECT COUNT(*)
FROM `players`
INNER JOIN `users`
ON `users`.`id` = `players`.`user_id`
INNER JOIN
(SELECT cities.*,
6371 *
acos(cos(radians(41.353312)) *
cos(radians(cities.latitude)) *
cos(radians(cities.longitude) - radians(1.976252)) +
sin(radians(41.353312))*sin(radians(cities.latitude))) AS km_away
FROM `cities`
HAVING km_away <= 20
ORDER BY km_away
) `cd`
ON `cd`.`id` = `users`.`city_id`
注意:我已经在内联视图中给出了cd
的别名(我将其视为城市距离的简写。
COUNT聚合只返回一行,因此不需要ORDER BY。如果更改SELECT列表,并希望按特定顺序返回行,请在最外层的查询中添加ORDER BY,例如
ORDER BY cd.km_away ASC
更新:
您应该能够引用cities
,players
,users
表中的任何列以及SELECT列表中的计算距离(km_away
)。当然,您可以指定要返回的列,而不是使用“。*”。但是`cd.km_away'可以在外部查询中引用(SELECT列表,WHERE子句,ORDER BY等)
SELECT cd.km_away
, cd.*
, players.*
, users.*
FROM `players`
INNER JOIN `users`
ON `users`.`id` = `players`.`user_id`
INNER JOIN
(SELECT cities.*,
6371 *
acos(cos(radians(41.353312)) *
cos(radians(cities.latitude)) *
cos(radians(cities.longitude) - radians(1.976252)) +
sin(radians(41.353312))*sin(radians(cities.latitude))) AS km_away
FROM `cities`
HAVING km_away <= 20
ORDER BY km_away
) `cd`
ON `cd`.`id` = `users`.`city_id`
ORDER BY cd.km_away
答案 1 :(得分:1)
您在GROUP BY子句中获得了ASC。你的意思是使用ORDER BY。
修改强> 请原谅我对mysql的无知。我更喜欢坚持使用标准方法,特别是当它们也是最简单的方法时。 OP在粗体文字中注明“哪些不起作用”,在阅读整个问题之前,我认为我的答案原来答案可能就是问题。
SELECT
6371 *
acos(cos(radians(41.353312)) *
cos(radians(cities.latitude)) *
cos(radians(cities.longitude) - radians(1.976252)) +
sin(radians(41.353312))*sin(radians(cities.latitude))) as km,
...
FROM
players
INNER JOIN users ON users.id = players. user_id
INNER JOIN cities ON cities.id = users.city_id
WHERE
6371 *
acos(cos(radians(41.353312)) *
cos(radians(cities.latitude)) *
cos(radians(cities.longitude) - radians(1.976252)) +
sin(radians(41.353312))*sin(radians(cities.latitude)))
<= 20
ORDER BY
6371 *
acos(cos(radians(41.353312)) *
cos(radians(cities.latitude)) *
cos(radians(cities.longitude) - radians(1.976252)) +
sin(radians(41.353312))*sin(radians(cities.latitude)))
ASC
派生表/虚拟表/内联视图可以清除它。
SELECT cities.km, ...
FROM
players
INNER JOIN users ON users.id = players. user_id
INNER JOIN
(
SELECT
cities.*, /* don't know if this works on mysql */
6371 *
acos(cos(radians(41.353312)) *
cos(radians(cities.latitude)) *
cos(radians(cities.longitude) - radians(1.976252)) +
sin(radians(41.353312))*sin(radians(cities.latitude))) as km
) as cities /* maybe another name is appropriate */
ON cities.id = users.city_id
WHERE cities.km <= 20
ORDER BY cities.km ASC