【问题标题】:Does ORDER BY apply before or after DISTINCT?ORDER BY 在 DISTINCT 之前还是之后适用?
【发布时间】:2012-06-05 21:10:11
【问题描述】:

在 MySQL 查询中,当使用 DISTINCT 选项时,ORDER BY 是否在删除重复项后应用?如果没有,有没有办法让它这样做?我认为这会导致我的代码出现一些问题。

编辑
这是有关导致我的问题的原因的更多信息。我明白,乍一看,这个顺序并不重要,因为我正在处理重复的行。但是,情况并非完全如此,因为我使用INNER JOIN 对行进行排序。

假设我有一个论坛线程表,其中包含以下数据:

+----+--------+-------------+
| id | userid |    title    |
+----+--------+-------------+
|  1 |      1 | Information |
|  2 |      1 | FAQ         |
|  3 |      2 | Support     |
+----+--------+-------------+

我在另一个表中也有一组帖子,如下所示:

+----+----------+--------+---------+
| id | threadid | userid | content |
+----+----------+--------+---------+
|  1 |        1 |      1 | Lorem   |
|  2 |        1 |      2 | Ipsum   |
|  3 |        2 |      2 | Test    |
|  4 |        3 |      1 | Foo     |
|  5 |        2 |      3 | Bar     |
|  6 |        3 |      5 | Bob     |
|  7 |        1 |      2 | Joe     |
+----+----------+--------+---------+

我正在使用以下 MySQL 查询来获取所有线程,然后根据最新帖子对它们进行排序(假设具有更高 id 的帖子更新:

SELECT t.*
FROM Threads t
INNER JOIN Posts p ON t.id = p.threadid
ORDER BY p.id DESC

这可行,并生成如下内容:

+----+--------+-------------+
| id | userid |    title    |
+----+--------+-------------+
|  1 |      1 | Information |
|  3 |      2 | Support     |
|  2 |      1 | FAQ         |
|  3 |      2 | Support     |
|  2 |      1 | FAQ         |
|  1 |      1 | Information |
|  1 |      1 | Information |
+----+--------+-------------+

但是,如您所见,信息是正确的,但存在重复的行。我想删除这样的重复,所以我改用SELECT DISTINCT。然而,这产生了以下结果:

+----+--------+-------------+
| id | userid |    title    |
+----+--------+-------------+
|  3 |      2 | Support     |
|  2 |      1 | FAQ         |
|  1 |      1 | Information |
+----+--------+-------------+

这显然是错误的,因为“信息”线程应该在顶部。似乎使用DISTINCT 会导致从上到下删除重复项,因此只剩下最后一行。这会导致排序出现一些问题。

是这样吗,还是我分析错了?

【问题讨论】:

  • 您认为它会导致什么问题?会有什么不同?
  • 为什么重要?在应用distinct之前或之后,顺序应该相同
  • 您能否向我们展示您正在尝试的内容以及您遇到的实际问题的示例查询?
  • @bfrohs - 对我来说没有任何意义。如果先对行进行排序,然后删除重复项,而不是先删除重复项,然后对剩余的内容进行排序,则会得到相同的结果。
  • @bfrohs,但使用 DISTINCT 你会得到 (1:a;1:c;2:b)。

标签: php mysql sql-order-by


【解决方案1】:

需要理解的两件事:

  1. 一般来说,结果集是unordered,除非您指定ORDER BY 子句;如果您指定 non-strict order(即在非唯一列上使用 ORDER BY),则在该排序下相等的记录出现在结果集中的顺序是未定义的。

    我怀疑您可能指定了这样一个非严格的顺序,这是您问题的根源:通过在一组足以唯一标识每个记录的列上指定 ORDER BY 来确保您的顺序是严格的你关心它在结果集中的最终位置。

  2. DISTINCT may use GROUP BY,导致结果按分组列排序;也就是说,SELECT DISTINCT a, b, c FROM t 将生成一个看起来好像 ORDER BY a, b, c 已被应用的结果集。同样,指定一个足够严格的顺序来满足您的需求将覆盖此效果。


根据您的更新,请记住我上面的第 2 点,很明显,将结果分组以实现 DISTINCT 的效果使得无法再按非分组列 p.id 进行排序;相反,你想要:

SELECT   t.*
FROM     Threads t INNER JOIN Posts p ON t.id = p.threadid
GROUP BY t.id
ORDER BY MAX(p.id) DESC

【讨论】:

  • 太棒了,谢谢,这行得通。所以,只是为了确认一下,MAX() 使用每个组中p.id 的最大值进行比较?
【解决方案2】:

DISTINCT 通知 MySQL 如何为您构建行集,ORDER BY 提示该行集应该如何呈现。所以答案是:DISTINCT 第一个,ORDER BY 最后一个。

【讨论】:

  • 但是,实际上,DISTINCT 是通过对结果进行排序来实现的......所以如果优化器对两个任务使用相同的排序,则可能不会。
  • 在这种情况下,正如 eggyval 指出的那样,有一个exception。当 DISTINCT 与 ORDER BY 分组时,它首先进行排序(文件排序)。
【解决方案3】:

DISTINCTORDER BY 的应用顺序在大多数情况下不会影响最终输出。

但是,如果您还使用GROUP BY,这影响最终输出。在这种情况下,ORDER BYGROUP BY 之后执行,这将返回意外结果(假设您希望在分组之前执行排序)。

【讨论】:

  • DISTINCT may use GROUP BYbefore 分组执行排序会实现之后执行它不会(请记住,选择没有聚合函数的未分组列会导致不确定的结果 - 在这种情况下无论如何都不相关,因为 DISTINCT 确保没有这样的列是否存在)?
  • @eggyal,问题不在于DISTINCT,而在于GROUP BYORDER BY。如果行被分组但未被选中,DISTINCT 没有任何帮助,并且查询可能返回“错误”的行值(例如,id,稍后用于检索值)。
猜你喜欢
  • 2011-06-25
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 2018-06-27
  • 1970-01-01
  • 2016-04-03
  • 1970-01-01
相关资源
最近更新 更多