Logical execution order: FROM β WHERE β GROUP BY β HAVING β SELECT β ORDER BY.
Thatβs why you can sort using aggregate aliases (e.g., TotalSales) in ORDER BY.
Example 1 β Top revenue by product (DESC) with name tie-break (ASC)
SELECT ProductName,
SUM(Quantity * UnitPrice) AS TotalSales
FROM OrderItems
GROUP BY ProductName
ORDER BY TotalSales DESC, ProductName ASC;
Groups rows per ProductName, then sorts groups by TotalSales (highest first), and alphabetically for ties.
Example 2 β Average salary by department & role (DESC, then ASC)
SELECT Department,
JobTitle,
AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY Department, JobTitle
ORDER BY AvgSalary DESC, Department ASC;
Multiple grouping columns are allowed. Sort directions can differ per column.
Example 3 β Keep only groups with β₯ 10 orders, then sort by count
SELECT CustomerID,
COUNT(*) AS OrderCount
FROM Orders
GROUP BY CustomerID
HAVING COUNT(*) >= 10
ORDER BY OrderCount DESC;
HAVING filters after grouping; the final list is then sorted by the aggregate alias.
β
You can ORDER BY an alias created in the SELECT list (e.g., TotalSales).
β
Positional sort works in many DBs: ORDER BY 2 DESC (sort by 2nd selected column). Use sparingly for readability.
β οΈ With DISTINCT, some systems require all ORDER BY columns to appear in the SELECT list.
β οΈ NULLS order varies by DB (e.g., PostgreSQL: NULLS FIRST|LAST). Check your engineβs behavior.