1

我有以下查询:

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

4

3 回答 3

4

这个查询是模棱两可的:

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

这是模棱两可的,因为它不保证它返回 MAX(TIME) 出现的行的 ID。它为 的每个不同值返回 MAX(TIME) caseID,但其他列的值(如 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 
于 2013-03-29T20:09:44.730 回答
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
于 2013-03-29T20:05:47.530 回答
1

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

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

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

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

于 2013-03-29T20:08:45.417 回答