【问题标题】:MySQL - Order by in Inner query. What am I missing?MySQL - 在内部查询中排序。我错过了什么?
【发布时间】:2012-07-20 03:37:56
【问题描述】:

我有以下表格和关系:

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

【问题讨论】:

  • +1。 (仅用于大圆计算)。

标签: mysql sql select inner-join subquery


【解决方案1】:

我不完全清楚您要返回什么结果集。但是看看你的问题,我想你想让你的子查询(+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 表中的任何列,以及 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

【讨论】:

  • 正如您对GROUP BY 的评论所述,我认为您需要WHERE 而不是HAVING。不反对您的回答,但这与我否决的回答基本相同吗?
  • 不知道为什么要写COUNT()。我实际上想得到所有的教授字段加上相关的用户字段,加上城市字段加上给定距离的计算距离......我可以选择教授。,但我看不到如何获得返回的每条教授记录的 km_away。
  • @shawnt:是的,这看起来与您答案中的最后一个查询基本相同。我没有对你的回答投反对票。但我认为否决票可能与您回答的最早部分有关。
  • 我没想到是你。在我添加更多细节后出现了反对票。我也讨厌从你的答案中拿走,但是在有子句中引用列别名是不标准的,并且排序应该只应用于最终结果集。如果它们有帮助,请务必使用扩展程序,但我并不想无礼。
  • @Hommer:更新了我对每个表中引用列的回答。我不清楚您问题的professors 部分,我在您的查询中没有看到任何类似的内容,我确定我只是错过了它。
【解决方案2】:

您在 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

【讨论】:

  • 好吧,我什至没有看过你的查询,但显然 mysql 比我想象的更奇怪。
  • @shant00:这是一个特定于 MySQL 的扩展,它允许在 GROUP BY 表达式之后使用 ASCDESC 关键字。
  • 我怀疑是这样的,但既然你真的只希望每组有一行,为什么不只是用户订购呢?
  • @shawnt00:我对您的回答加了 +1 票。您可能会考虑改写您对 OP 意图的原始想法,提到在 GROUP BY 上使用 ASC 和 DESC 关键字是对 ANSI SQL 的 MySQL 特定扩展,并且使用这种扩展不会获得你什么,最好避免使用。类似的东西。
  • @shawnt00:km &lt;= 20 谓词可以包含在内联视图中。如果没有关于这个表达式的谓词,当 MySQL 将视图具体化为临时 MyISAM 表时,它基本上会创建整个 cities 表的副本。任何过滤掉行的谓词(甚至是 HAVING 子句)都会导致临时表变小。
猜你喜欢
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 2014-12-09
  • 1970-01-01
  • 2017-03-02
  • 2013-08-01
  • 1970-01-01
相关资源
最近更新 更多