如何在 SQL 查询中对 LEFT JOIN 的顺序进行排序?

Posted

技术标签:

【中文标题】如何在 SQL 查询中对 LEFT JOIN 的顺序进行排序?【英文标题】:how to sort order of LEFT JOIN in SQL query? 【发布时间】:2011-07-18 08:31:31 【问题描述】:

好的,我尝试用谷歌搜索疯狂的答案,但我无法解决这个问题,所以我希望有人能够提供帮助。

假设我有一个用户表,非常简单的表:

id | userName
3    Michael
4    Mike
5    George

我还有另一张关于他们的汽车和价格的表格。

id | belongsToUser | carPrice
1    4               5000
2    4               6000
3    4               8000

现在我需要做的是这样的事情(随意重写):

   SELECT
      `userName`,
      `carPrice`
   FROM `users`
   LEFT JOIN `cars`
   ON cars.belongsToUser=users.id
   WHERE `id`='4'

返回:

Mike | 5000

但我需要某个用户最贵的车,而不是找到的第一个条目。

所以问题:如何设置 LEFT JOIN 表以按 carPrice、DESC 排序?

【问题讨论】:

应该返回所有 3 条记录,为什么它只返回 1 条......我们错过了什么? 你没有显示整个查询,它应该返回三个结果 当您说“按 carPrice DESC 订购”时,您的意思是您想要所有匹配的汽车,按价格订购吗?还是您的意思是您希望加入只获得一辆匹配的汽车,而那辆汽车是最昂贵的? 【参考方案1】:

旧的 mysql 版本就足够了:

SELECT
    `userName`,
    `carPrice`
FROM `users`
LEFT JOIN (SELECT * FROM `cars` ORDER BY `carPrice`) as `cars`
ON cars.belongsToUser=users.id
WHERE `id`='4'

现在,如果您使用 MariaDB,子查询应该是有限

SELECT
    `userName`,
    `carPrice`
FROM `users`
LEFT JOIN (SELECT * FROM `cars` ORDER BY `carPrice` LIMIT 18446744073709551615) as `cars`
ON cars.belongsToUser=users.id
WHERE `id`='4'

【讨论】:

在你的答案中添加一个小解释通常很有用 除非您别无选择,否则请始终尽量避免这样的子选择。这可能适用于小型数据集,但开始处理数千或数百万行时,您最多会遇到性能问题。【参考方案2】:

这将为用户提供最昂贵的汽车:

SELECT users.userName, MAX(cars.carPrice)
FROM users
LEFT JOIN cars ON cars.belongsToUser=users.id
WHERE users.id=4
GROUP BY users.userName

但是,这句话让我觉得您希望所有汽车价格按降序排列:

所以问题:如何设置 LEFT JOIN 表以按 carPrice、DESC 排序?

所以你可以试试这个:

SELECT users.userName, cars.carPrice
FROM users
LEFT JOIN cars ON cars.belongsToUser=users.id
WHERE users.id=4
GROUP BY users.userName
ORDER BY users.userName ASC, cars.carPrice DESC

【讨论】:

【参考方案3】:

尝试使用MAXGROUP BY

SELECT u.userName, MAX(c.carPrice)
FROM users u
    LEFT JOIN cars c ON u.id = c.belongsToUser
WHERE u.id = 4;
GROUP BY u.userName;

更多信息GROUP BY

group by 子句用于根据 group by 列的唯一组合将所选记录分成组。然后,这允许我们使用将依次应用于每组记录的聚合函数(例如 MAX、MIN、SUM、AVG...)。数据库将为每个分组返回一条结果记录。

例如,如果我们在这样的表中有一组表示温度随时间和位置变化的记录:

Location   Time    Temperature
--------   ----    -----------
London     12:00          10.0
Bristol    12:00          12.0
Glasgow    12:00           5.0
London     13:00          14.0
Bristol    13:00          13.0
Glasgow    13:00           7.0
...

那么如果我们想通过位置找到最高温度,那么我们需要将温度记录分成多个组,其中特定组中的每个记录具有相同的位置。然后我们想找到每组的最高温度。执行此操作的查询如下:

SELECT Location, MAX(Temperature)
FROM Temperatures
GROUP BY Location;

【讨论】:

感谢您的帮助,如果您能进一步解释 GROUP BY 的用途,因为没有它,查询似乎返回相同的数据 添加了一些关于 group by 的进一步解释 非常好的解决方案。结合 MAX() 和 GROUP BY 会产生一个我没有预料到但效果很好的结果。对于当 tableB 有多行并且您想要加入特定行时的 LEFT JOIN。谢谢!【参考方案4】:

其他几个答案给出了使用 MAX 的解决方案。在某些情况下,使用聚合函数要么不可能,要么性能不佳。

我经常使用的替代方法是在连接中使用相关子查询...

SELECT
   `userName`,
   `carPrice`
FROM `users`
LEFT JOIN `cars`
ON cars.id = (
  SELECT id FROM `cars` WHERE BelongsToUser = users.id ORDER BY carPrice DESC LIMIT 1
)
WHERE `id`='4'

【讨论】:

那些场景是什么(帮助人们在子查询和group by之间做出决定)? 如果cars 表包含其他信息,例如品牌、型号、牌照等。此方法查找单个记录及其所有字段。 MAX() 方法只找到一个字段的值。这取决于问题的真正意图(最高价格)与(最高价格的汽车)【参考方案5】:

试试这个:

   SELECT
      `userName`,
      `carPrice`
   FROM `users`
   LEFT JOIN `cars`
   ON cars.belongsToUser=users.id
   WHERE `id`='4'
   ORDER BY `carPrice` DESC
   LIMIT 1

菲利克斯

【讨论】:

ORDER BY carPrice DESC,你的意思是?这将适用于单个用户,是的。但不是多个。 @djacobson 他正在按用户 ID 进行过滤。所以 group by 是一个更通用的解决方案。另一方面,如果他真的一直按用户 ID 过滤,这是一个更快的解决方案

以上是关于如何在 SQL 查询中对 LEFT JOIN 的顺序进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Teradata SQL 中使用 LEFT JOIN 对查询中的非聚合参数进行 GROUP BY?

如何使用 LEFT JOIN 查询将 RAW SQL 转换为 DQL

Sql查询left join

在 sql 查询中使用 LIMIT 和 ORDER BY 和 LEFT JOIN

SQL Server 在视图查询中将 LEFT JOIN 替换为 LEFT OUTER JOIN

关于SQL 查询效率问题 left join 改成 inner join union