【问题标题】: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:这就是我要做的事情:stackoverflow.com/questions/13216762/…

标签: mysql inner-join


【解决方案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 在实际查询中击败了我,但这是您想要的方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2012-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多