Lesson Description
One row per group instead of one per input row.
Lesson 2 of 4
Progress: 0/4 exercises solved (0%)
Solve all exercises below to unlock the next lesson.
Lesson Description
One row per group instead of one per input row.
Easy Project
Mini project: Produce an executive KPI table with totals and averages per department, sorted by highest business impact.
GROUP BY splits rows into groups by the values of one or more columns, then applies an aggregate function to each group.
SELECT grouping_column, aggregate_function(col)
FROM table_name
GROUP BY grouping_column;
SELECT department_id, COUNT(*) AS employee_count
FROM employees
GROUP BY department_id
ORDER BY department_id;
One row is returned per distinct department_id.
SELECT department_id, job_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id, job_id
ORDER BY department_id, job_id;
Every column in SELECT must either be listed in GROUP BY or wrapped in an aggregate function. Non-grouped, non-aggregated columns are ambiguous — PostgreSQL will reject them.
-- ERROR: first_name not in GROUP BY and not aggregated
SELECT department_id, first_name, COUNT(*)
FROM employees
GROUP BY department_id;
WHERE → GROUP BY → SELECT → ORDER BY
You can filter rows before grouping with WHERE, and filter groups after grouping with HAVING (next lesson).
GROUP BY can use a column position number: GROUP BY 1 means the first column in SELECT.GROUP BY an expression: GROUP BY DATE_TRUNC('month', hire_date).This lesson is part of Aggregations & Grouping. Focus on the core idea in GROUP BY, then validate with deliberate practice.
What to master
Common mistakes
High-level strategy
Task ladder
Transparent data checks
Retention loop
Logical reasoning for commands
GROUP BY
Why: Defines one output row per grouping key.
Memory cue: Group key = output row identity.
HAVING
Why: Filters after aggregates are calculated.
Memory cue: WHERE before groups, HAVING after groups.
COUNT / SUM / AVG
Why: Converts row-level data into business metrics.
Memory cue: Measure only after grain is correct.
Concept check
3 quick questions. One at a time. Instant score at the end.
Return department_id and employee_count for every department in the HR sandbox.
From the store sandbox, return status and the number of orders (order_count) in each status.
From the store sandbox, return category_id and product_count (the number of products in each category), ordered by category_id.
From the hospital sandbox, return each appointment status and the number of appointments in that status (appt_count), ordered by status.
Lesson 2 of 4
0/4 solved (0%)
Finish this lesson to unlock next.