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
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
WHEREfilters rows before groupingHAVINGfilters groups after grouping
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 doneStep 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).
SELECT city FROM customers;
Output appears here. Press Run or Ctrl/⌘ + Enter.
Step 2 of 2 · Big spenders
From orders, return each customer_id and their total quantity ordered (as items), but only customers with 3 or more items. Order by customer_id.
SELECT customer_id, quantity FROM orders;
Output appears here. Press Run or Ctrl/⌘ + Enter.
✅ Check your understanding
WHERE vs HAVING. Which filters groups after they're summarized?
Create a free account to track your progress.