1

我有以下表格和关系:

Players:
foreign_key to User  

Users:
foreign_key to City

Cities:
latitude (float)
longitude (float)

我正在尝试获取关联用户来自给定城市或 near_by 城市的所有教授。

我有这个查询,它返回给定特定纬度和经度的 near_by(20 公里)城市以及到给定城市纬度和经度的距离。在这种情况下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

我已经尝试了这个查询(它不起作用),我希望它返回给我的关联用户城市在给定城市附近的玩家(纬度和经度)。

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 - 获取返回的每条记录中的距离(值)。

4

2 回答 2

2

我不完全清楚您要返回的结果集。但是看看你的问题,我想你想让你的子查询(+1!用于从巴塞罗那的距离的“大圆距离”计算!)作为行源。

一种方法是将子查询用作“内联视图”,而不是在 WHERE 子句中引用它。

由于该查询返回了城市表中的所有列,因此它基本上可以替换查询中的城市表。

不需要 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

更新:

您应该能够引用citiesplayersusers表中的任何列,以及km_awaySELECT 列表中的计算距离 ( )。当然,您将指定要返回的列,而不是使用“.*”。但是 `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
于 2012-07-20T21:09:32.400 回答
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
于 2012-07-20T20:27:39.530 回答