Give priority to ORDER BY over a GROUP BY in MySQL without subquery

梦想的初衷 提交于 2019-12-04 05:42:05

This should do it and work pretty well as long as there is a composite index on (program,id). The subquery should only inspect the very first id for each program branch, and quickly retrieve the required record from the outer query.

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

By definition, ORDER BY is processed after grouping with GROUP BY. By definition, the conceptual way any SELECT statement is processed is:

  1. Compute the cartesian product of all tables referenced in the FROM clause
  2. Apply the join criteria from the FROM clause to filter the results
  3. Apply the filter criteria in the WHERE clause to further filter the results
  4. Group the results into subsets based on the GROUP BY clause, collapsing the results to a single row for each such subset and computing the values of any aggregate functions -- SUM(), MAX(), AVG(), etc. -- for each such subset. Note that if no GROUP BY clause is specified, the results are treated as if there is a single subset and any aggregate functions apply to the entire results set, collapsing it to a single row.
  5. Filter the now-grouped results based on the HAVING clause.
  6. Sort the results based on the ORDER BY clause.

The only columns allowed in the results set of a SELECT with a GROUP BY clause are, of course,

  • The columns referenced in the GROUP BY clause
  • Aggregate functions (such as MAX())
  • literal/constants
  • expresssions derived from any of the above.

Only broken SQL implementations allow things like select xxx,yyy,a,b,c FROM foo GROUP BY xxx,yyy — the references to colulmsn a, b and c are meaningless/undefined, given that the individual groups have been collapsed to a single row,

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
        )

Create an index on (program, id) for this to work fast.

Regarding your original query:

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

This query would not parse in any SQL dialect except MySQL.

It abuses MySQL's ability to return ungrouped and unaggregated expressions from a GROUP BY statement.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!