Lesson 5 of 10 · 9 min · 2 hands-on steps

Grouping Results with GROUP BY

One summary row per category, the query behind every dashboard.

One row per group

SQL · try it
SELECT department_id, COUNT(*) AS people, ROUND(AVG(salary)) AS avg_salary
FROM employees
GROUP BY department_id;

GROUP BY splits the rows into piles (one per department), then the aggregate runs on each pile.

WHERE vs HAVING

  • WHERE filters rows before grouping
  • HAVING filters groups after grouping
SQL · try it
SELECT department_id, COUNT(*) AS people
FROM employees
WHERE hired >= '2021-01-01'   -- only recent hires…
GROUP BY department_id
HAVING COUNT(*) >= 2;         -- …in departments with at least 2 of them

The rule that trips everyone up

Every column in SELECT must either be in GROUP BY or inside an aggregate. Ask yourself: "which name would it show for a group of three people?" If there's no single answer, the query doesn't make sense.

Interview favorite: "Count orders per customer and show only customers with more than N orders." That's GROUP BY + HAVING.

🧪 Practice: 2 steps

0 / 2 done

Step 1 of 2 · Customers per city

Return each city and how many customers it has as customers, most customers first (break ties alphabetically by city).

SQL
SELECT city FROM customers;

Output appears here. Press Run or Ctrl/⌘ + Enter.

✅ Check your understanding

  1. WHERE vs HAVING. Which filters groups after they're summarized?

Create a free account to track your progress.