为什么'ORDER BY'需要从MySQL加入中获得正确的结果?

时间:2013-03-29 19:48:25

标签: mysql inner-join

我有以下查询:

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是一种具有不同时间戳的多个条目的对象。

3 个答案:

答案 0 :(得分:4)

此查询不明确:

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

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

在实践中,MySQL会按照存储顺序扫描行时选择在组中找到 first 的行。

示例:

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允许它,相信你知道如何形成一个明确的查询。

修复是使用select-list only 中的列,如果它们是明确的,也就是说,如果它们在GROUP BY子句中,那么每个组都保证只有一个不同的值:

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

您正在看到该问题,因为您获得了每个caseID的MAX(TIME),但由于您按caseID和NOT ID进行分组,因此您将获得一个任意ID。之所以发生这种情况,是因为当您使用聚合函数(如MAX)时,必须为选择中的每个非分组字段指定聚合函数的方式。这意味着,如果它在SELECT BY中而不在GROUP BY中,则必须告诉MySQL如何聚合。如果你没有,那么你得到一个RANDOM行(好吧,不是随机本身,但它不会按照你一定期望的顺序)。

ORDER BY为你工作的原因是它有点欺骗查询优化器在分组之前对结果进行排序,这恰好产生了你想要的结果,但是要警告,情况并非总是如此

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

Barmar打败了我的实际查询,但这就是你想要的方式。