MySQL - 在内部查询中排序。我错过了什么?

时间:2012-07-20 20:24:43

标签: mysql sql select inner-join subquery

我有以下表格和关系:

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

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

更新:

您应该能够引用citiesplayersusers表中的任何列以及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