The short answer
GROUP BY comes before ORDER BY — no exceptions. This is true two ways at once: it's the required syntax order, and it's the logical execution order. Group the rows, then sort the groups.
-- ✅ Group first, then sort the grouped result
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department
ORDER BY headcount DESC;
-- ❌ Syntax error: ORDER BY cannot come before GROUP BY
SELECT department, COUNT(*)
FROM employees
ORDER BY department
GROUP BY department;
Written order vs execution order
SQL requires clauses in a fixed sequence, and evaluates them in a different (but consistent) sequence. In both, GROUP BY precedes ORDER BY:
| Required written order | Logical execution order |
|---|---|
| SELECT | FROM / JOIN |
| FROM | WHERE |
| WHERE | GROUP BY |
| GROUP BY | HAVING |
| HAVING | SELECT |
| ORDER BY | ORDER BY |
| LIMIT | LIMIT |
Since ORDER BY runs after SELECT, it can "see" everything the query has already produced — grouped columns, aggregates, and aliases. For the full pipeline, see SQL execution order explained.
What you CAN sort by after GROUP BY
In a grouped query, ORDER BY may reference:
- Any column in the
GROUP BYlist (e.g.ORDER BY department). - Any aggregate (e.g.
ORDER BY COUNT(*) DESC,ORDER BY SUM(amount)). - Any alias defined in
SELECT(e.g.ORDER BY headcount). - An ordinal position (e.g.
ORDER BY 2) — though naming the column or alias is clearer.
Sorting by an aggregate (top-N groups)
Sorting by an aggregate is how you build "top N" reports. Combine it with LIMIT:
-- Five departments with the most employees
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department
ORDER BY COUNT(*) DESC
LIMIT 5;
Note that LIMIT runs after ORDER BY, so it correctly takes the top 5 of the sorted result — not five random groups.
Sorting by a SELECT alias
Because ORDER BY is evaluated after SELECT, aliases you created there are available — the opposite of WHERE, which runs before SELECT and can't see them.
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC; -- alias works in ORDER BY
What you can't ORDER BY
The grouping rule applies to ORDER BY too: a column that isn't in GROUP BY and isn't aggregated has no single value per group, so you can't sort by it.
-- ❌ salary isn't grouped or aggregated
SELECT department, COUNT(*)
FROM employees
GROUP BY department
ORDER BY salary;
-- ✅ Sort by an aggregate of salary instead
SELECT department, COUNT(*)
FROM employees
GROUP BY department
ORDER BY AVG(salary) DESC;
GROUP BY doesn't sort
A frequent assumption is that GROUP BY returns groups in sorted order "for free." It doesn't — grouping and sorting are separate operations, and the order you happen to get can change with indexes or engine versions. If you need a specific order, always add ORDER BY. (More on this in GROUP BY mistakes that break SQL queries.)
Full clause order reference
| Clause | Purpose | Must be written… |
|---|---|---|
| WHERE | Filter rows | before GROUP BY |
| GROUP BY | Form groups | after WHERE |
| HAVING | Filter groups | after GROUP BY |
| ORDER BY | Sort the result | after HAVING |
| LIMIT / OFFSET | Trim the result | last |
Key takeaways
ORDER BYalways comes afterGROUP BY— in syntax and in execution.- Writing
ORDER BYbeforeGROUP BYis a syntax error. - You can sort by grouped columns, aggregates, and
SELECTaliases. - You can't sort by a column that's neither grouped nor aggregated.
GROUP BYnever sorts — addORDER BYto guarantee order;LIMITruns last.