为啥需要“ORDER BY”才能从 MySQL 连接中获得正确的结果?

Posted

技术标签:

【中文标题】为啥需要“ORDER BY”才能从 MySQL 连接中获得正确的结果?【英文标题】:Why is 'ORDER BY' needed to get correct result from MySQL join?为什么需要“ORDER BY”才能从 MySQL 连接中获得正确的结果? 【发布时间】:2013-03-29 19:48:25 【问题描述】:

我有以下疑问:

SELECT t.ID, t.caseID, time
FROM tbl_test t
INNER JOIN (
    SELECT ID, MAX( TIME ) 
    FROM tbl_test
    WHERE TIME <=1353143351
    GROUP BY caseID 
    ORDER BY caseID DESC -- ERROR HERE!
) s
USING (ID)

似乎只有在内部连接中使用ORDER BY 才能得到正确的结果。这是为什么?我正在使用 ID 进行连接,所以订单应该没有影响。 如果我删除订单,我会从数据库中获得太旧的条目。 ID是主键,caseID是一种具有多个不同时间戳的条目的对象。

【问题讨论】:

您能用文字解释一下您要做什么吗? 您需要在子查询中GROUP BY ID 列。 mysql 允许你正在做的事情,但返回不可预知的结果...... 你依赖于 MySQL 破坏的非标准和非保证 group by 行为。 派生表(又名“子查询”)中的order by 没有任何意义(至少不是没有限制)。您应该对整体结果进行排序。 @Mike Brant:这就是我要做的事情:***.com/questions/13216762/… 【参考方案1】:

这个查询不明确:

SELECT ID, MAX( TIME ) 
FROM tbl_test
WHERE TIME <=1353143351
GROUP BY caseID 

这是模棱两可的,因为它不保证它返回出现 MAX(TIME) 的行的 ID。它为caseID 的每个不同值返回 MAX(TIME),但其他列的值(如 ID)是从组成员中任意选择的。

实际上,MySQL 会在按存储顺序扫描行时选择它在组中找到第一个的行。

例子:

caseID  ID  time
  1     10  15:00
  1     12  18:00
  1     14  13:00

最大时间为 18:00,即 ID 为 12 的行。但查询将返回 ID 10,因为它是组中的第一个。如果您要使用 ORDER BY 反转顺序,它将返回 ID 14。仍然不是找到最大时间的行,而是来自行组的另一端。

您的查询适用于ORDER BY caseID DESC,因为巧合的是,您的时间值会随着 ID 的增加而增加。

这种查询实际上是标准 SQL 和大多数其他品牌的 SQL 数据库中的错误。 MySQL 允许这样做,相信您知道如何形成明确的查询。

解决方法是在选择列表中使用列如果它们是明确的,也就是说,如果它们在 GROUP BY 子句中,那么每个组都保证只有一个不同的值:

SELECT caseID, MAX( TIME ) 
FROM tbl_test
WHERE TIME <=1353143351
GROUP BY caseID 

【讨论】:

【参考方案2】:
SELECT t.ID, t.caseID, time
FROM tbl_test t
INNER JOIN (
    SELECT caseID, MAX( TIME ) maxtime
    FROM tbl_test
    WHERE TIME <=1353143351
    GROUP BY caseID
) s
ON t.caseID = s.caseID and t.time = s.maxtime

【讨论】:

我会在 TIME 左右添加 ticks,因为它是保留关键字。 我不会,因为它不是! ;-)【参考方案3】:

您看到该问题是因为您获得了每个 caseID 的 MAX(TIME),但由于您是按 caseID 而不是 ID 分组,因此您获得的是任意 ID。发生这种情况是因为当您使用 MAX 等聚合函数时,您必须为 选择中的每个非分组字段指定您希望如何聚合它。这意味着,如果它在 SELECT 中而不在 GROUP BY 中,您必须告诉 MySQL 如何聚合。如果你不这样做,那么你会得到一个 RANDOM 行(嗯,不是 random 本身,但它不会按照你所期望的顺序)。

ORDER BY 为您工作的原因是,它会欺骗查询优化器在分组之前对结果进行排序,这恰好会产生您想要的结果,但请注意,情况并非总是如此.

您想要的是具有给定 caseID 的 MAX(TIME) 的 ID。这意味着您的 INNER 连接需要通过 caseID(而不是 ID)和时间(这将为您在外部表中的每 1 行提供 1 行)进行连接。

Barmar 在实际查询中击败了我,但这是您想要的方式。

【讨论】:

以上是关于为啥需要“ORDER BY”才能从 MySQL 连接中获得正确的结果?的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL:为啥两个几乎相同的查询的 ORDER BY 时间不同

为啥在mysql中第一个union两个子句的order by不起作用

为啥 MySQL 查询在使用 LIMIT 和 Order BY 时会变慢?

如果 ASC 和 DESC 混合使用,为啥 MySQL 不能为 ORDER BY 使用索引?

mysql select * order by 索引 limit0,10 为啥是全表扫描

mysql中order by分别 按两张表相同的属性排序为啥结果不一样