GROUP BY & HAVING
GROUP BY splits rows into groups by a column and applies the aggregate to each group. “How many employees per department?” is exactly a GROUP BY.
SQL
SELECT dept_id, COUNT(*) AS staff, AVG(salary) AS avg_salary FROM employees GROUP BY dept_id;
WHERE filters rows before grouping; HAVING filters groups after grouping:
SQL
SELECT status, COUNT(*) AS orders FROM orders GROUP BY status HAVING COUNT(*) >= 3;
Watch outKey rule: every column in SELECT without an aggregate must appear in GROUP BY.