【问题标题】:Give priority to ORDER BY over a GROUP BY in MySQL without subquery在没有子查询的情况下,MySQL 中的 ORDER BY 优先于 GROUP BY
【发布时间】:2011-06-10 14:58:10
【问题描述】:

我有以下查询可以满足我的要求,但我怀疑没有子查询也可以做到这一点:

  SELECT * 
    FROM (SELECT * 
            FROM 'versions' 
        ORDER BY 'ID' DESC) AS X 
GROUP BY 'program'

我需要的是按程序分组,但返回“ID”值最高的版本中的对象的结果。

根据我过去的经验,像这样的查询应该在 MySQL 中工作,但由于某种原因,它不是:

  SELECT * 
    FROM 'versions' 
GROUP BY 'program' 
ORDER BY MAX('ID') DESC

想要做的是让 MySQL 先执行 ORDER BY,然后执行 GROUP BY,但它坚持先执行 GROUP BY,然后再执行 ORDER BY .即它是对分组的结果进行排序,而不是对排序的结果进行分组。

当然不能写

SELECT * FROM 'versions' ORDER BY 'ID' DESC GROUP BY 'program'

谢谢。

【问题讨论】:

标签: sql mysql group-by sql-order-by subquery


【解决方案1】:
SELECT  v.*
FROM    (
        SELECT  DISTINCT program
        FROM    versions
        ) vd
JOIN    versions v
ON      v.id = 
        (
        SELECT  vi.id
        FROM    versions vi
        WHERE   vi.program = vd.program
        ORDER BY
                vi.program DESC, vi.id DESC
        LIMIT 1
        )

(program, id) 上创建一个索引以使其快速工作。

关于您的原始查询:

SELECT * FROM 'versions' GROUP BY 'program' ORDER BY MAX('ID') DESC

除了MySQL 之外,此查询不会解析为任何SQL 方言。

它滥用了MySQLGROUP BY 语句返回未分组和未聚合表达式的能力。

【讨论】:

  • 这不是比我当前的查询重吗?它有两个子查询都需要访问数据库,而我目前使用的子查询有一个来自数据库,然后在内存中查询这个临时表的结果....
  • wrt 你的编辑:是的,这对我来说很好。这是一个内部网络应用程序,除了 MySQL 不会使用任何东西。但即便如此,它也不起作用。哦,它适用于 SQLite。
  • @ComputerGuru:您当前的查询是错误的,因此无论是重还是轻都无关紧要。只要您在program, id 上有一个索引,查询就会很有效:它将使用松散的索引扫描来执行DISTINCT,并使用单个索引搜索在每个组中查找ORDER BY / LIMIT 1DISTINCT 列表的大小小于完整的记录集。
  • @ComputerGuru:在你的帖子中都是。他们在“错误”中是错误的:他们在每个组中返回一个 random 记录。不保证他们返回的记录是持有MAX(id) 的记录。由于各种情况,查询现在可能会从GROUP BY 查询中返回包含MAX(id) 的记录,因为它是它在途中首先找到的记录。但是,当结果集不再适合内存时,GROUP BY 将需要分几个步骤完成,此时您的查询将中断。
  • @ComputerGuru:参见explainextended.com/2010/11/03/…,示例43
【解决方案2】:

根据定义,ORDER BY与 GROUP BY 分组后处理。根据定义,处理任何 SELECT 语句的概念方式是:

  1. 计算 FROM 子句中引用的所有表的笛卡尔积
  2. 应用 FROM 子句中的连接条件来过滤结果
  3. 在 WHERE 子句中应用过滤条件以进一步过滤结果
  4. 根据 GROUP BY 子句将结果分组为子集,将每个此类子集的结果折叠到一行并计算任何聚合函数的值 -- SUM()MAX()AVG() 等。 -- 对于每个这样的子集。请注意,如果未指定 GROUP BY 子句,则将结果视为只有一个子集,并且任何聚合函数都适用于整个结果集,并将其折叠为一行。
  5. 根据 HAVING 子句过滤现在分组的结果。
  6. 根据 ORDER BY 子句对结果进行排序。

当然,在带有 GROUP BY 子句的 SELECT 的结果集中允许的唯一列是

  • GROUP BY 子句中引用的列
  • 聚合函数(如MAX()
  • 文字/常量
  • 源自上述任何一种的表达式。

只有损坏的 SQL 实现才允许像 select xxx,yyy,a,b,c FROM foo GROUP BY xxx,yyy 这样的事情——对列 a、b 和 c 的引用是没有意义的/未定义的,因为各个组已被折叠到一行,

【讨论】:

  • 我不同意“破碎”的部分。在极少数情况下,“未定义”是一种想要的行为,例如“随机”。
  • 这是违反 ISO 9075 的行为。
  • 当其中一个表在PRIMARY KEY 上连接时,添加此行为是为了简化与GROUP BY 的连接,如下所示:SELECT a.*, SUM(b.value) FROM a JOIN b ON b.a = a.id GROUP BY a.id。通常,您需要将a 中的所有字段添加到GROUP BY,尽管a 中的所有值都保证在组内相同。
【解决方案3】:

只要 (program,id) 上有一个复合索引,这应该可以做到并且工作得很好。子查询应该只检查每个程序分支的第一个 id,并从外部查询中快速检索所需的记录。

select v.*
from
(
    select program, MAX(id) id
    from versions
    group by program
) m
inner join versions v on m.program=v.program and m.id=v.id

【讨论】:

  • 虽然id 通常是PRIMARY KEY,但在这种情况下可能不是,id 上可能有重复项。然后可以返回每个program 的多条记录。
  • @Quassnoi - 我理解,但这与您的提议有何不同?我更喜欢便携式查询。我也看不到“DISTINCT 程序”子查询中的值,但我可能遗漏了一些东西..
  • @cyberwiki:再看一遍我发现它没有,因为我的查询依赖于 id 也是唯一的。如果@op 想要在另一列上订购,我的评论会很有意义。有了索引,DISTINCTGROUP BY 针对松散扫描进行了优化,所以这些查询基本相同。 +1
  • 问题中的“无子查询”,接受答案中的子查询 =(
猜你喜欢
  • 2012-12-31
  • 2012-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-18
  • 1970-01-01
  • 2019-01-21
  • 1970-01-01
相关资源
最近更新 更多