为啥需要“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 使用索引?