Learn / Programming / SQL / Sorting and Aggregates

Beginner 15 min

Sorting and Aggregates

ORDER BY, LIMIT, COUNT, SUM, AVG and GROUP BY with HAVING.

What you will learn

  • Sort and paginate
  • Summarize with aggregates
  • Group rows

So far we have listed rows. Real questions are usually about order (who is biggest?) and summaries (how much in total?). This lesson covers both.

SELECT name, age FROM customers
ORDER BY age DESC, name ASC
LIMIT 2;
Output
name  | age
Grace | 45
Ada   | 36

ORDER BY sorts ascending by default; add DESC for descending and list several columns to break ties. LIMIT n keeps the first n rows, and OFFSET skips rows for pagination. Without ORDER BY, row order is not guaranteed.

Aggregate functions

Aggregates collapse many rows into one value: COUNT, SUM, AVG, MIN, MAX.

SELECT COUNT(*)       AS orders,
       SUM(total)     AS revenue,
       AVG(total)     AS average,
       MAX(total)     AS biggest
FROM orders
WHERE status = 'paid';
Output
orders | revenue | average | biggest
2      | 155.5   | 77.75   | 120.0

COUNT(*) counts rows; COUNT(column) counts rows where the column is not NULL; COUNT(DISTINCT column) counts unique values.

GROUP BY

GROUP BY splits rows into buckets and runs the aggregates once per bucket.

SELECT customer_id, COUNT(*) AS orders, SUM(total) AS spent
FROM orders
GROUP BY customer_id
ORDER BY spent DESC;
Output
customer_id | orders | spent
1           | 2      | 155.5
3           | 1      | 80.0

The rule: every column in SELECT must either appear in GROUP BY or be inside an aggregate function.

HAVING versus WHERE

WHERE filters rows before grouping; HAVING filters the groups after aggregation.

SELECT customer_id, SUM(total) AS spent
FROM orders
WHERE status = 'paid'          -- rows first
GROUP BY customer_id
HAVING SUM(total) > 100;       -- then groups
Logical order

SQL runs clauses in this order: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT. That is why you cannot use a SELECT alias inside WHERE.

Try it yourself

Find the number of customers in each country, showing only countries with two or more customers, most first.

Show solution
SELECT country, COUNT(*) AS customers
FROM customers
GROUP BY country
HAVING COUNT(*) >= 2
ORDER BY customers DESC;