Chapter 38: PostgreSQL GROUP BY Clause

The GROUP BY clause β˜•πŸ“Š

You already know:

  • SELECT, WHERE, ORDER BY, LIMIT
  • Aggregates like COUNT, SUM, AVG, MIN, MAX
  • JOIN, UNION

Now we reach GROUP BY β€” the command that says:

β€œI don’t want one big total β€” I want totals per group.”

Without GROUP BY β†’ aggregates give you one single number for the whole table. With GROUP BY β†’ you get one number per category (per city, per year, per course, per customer, etc.).

This is how almost every real dashboard, report, and analytics query is built.

1. What GROUP BY actually does (teacher drawing on imaginary board)

Imagine your students table has 100 rows.

You want:

  • Not the overall average GPA
  • But average GPA per enrollment_year
  • Or number of students per city
  • Or total fees paid per status

GROUP BY says:

  1. Split the rows into groups based on the value(s) in the GROUP BY column(s)
  2. For each group β†’ calculate the aggregates (COUNT, AVG, SUM…) separately
  3. Return one row per group with the aggregate results

2. Basic syntax skeleton (memorize this shape)

SQL

Golden rule #1 (the one most beginners break):

Every column in the SELECT list that is not inside an aggregate function must appear in the GROUP BY clause (or be functionally dependent on it).

3. Real, detailed examples – using our students table

Current students data (simplified + added city & fees_paid columns):

id first_name last_name city enrollment_year gpa fees_paid
1 Aarav Patel Hyderabad 2025 8.95 TRUE
2 Priya Reddy Secunderabad 2024 9.60 FALSE
3 Rahul Sharma Hyderabad 2025 7.85 FALSE
4 Sneha Kumar Hyderabad 2025 9.20 TRUE
5 Vikram Naik Hyderabad 2025 8.40 TRUE
6 Meera Iyer Secunderabad 2025 10.00 TRUE

Example 1: Average GPA per enrollment year (classic GROUP BY)

SQL

Result:

text

β†’ One row per year β†’ aggregates calculated separately for each year

Example 2: Students & fees status per city

SQL

Result:

text

β†’ Groups by two columns β†’ 4 groups total

Example 3: Wrong query (the famous error beginners make)

SQL

Fix β†’ add GROUP BY:

SQL

Or β†’ if you really want one row β†’ remove non-aggregated columns or wrap them:

SQL

Example 4: GROUP BY + HAVING (filter after grouping)

SQL

Result (example):

text

β†’ HAVING filters groups (after aggregation) β†’ WHERE would filter individual rows (before grouping)

4. Very important rules & gotchas (2026 PostgreSQL reality)

Rule / Mistake What happens Correct way / Explanation
Non-aggregated column not in GROUP BY ERROR: must appear in GROUP BY or aggregate Add to GROUP BY or wrap in aggregate (MIN, MAX, STRING_AGG…)
GROUP BY with no aggregate functions Works β€” but just removes duplicates (like DISTINCT) Use DISTINCT instead β€” clearer
NULL values in GROUP BY column All NULLs go into one group Normal & correct behavior
GROUP BY ordinal position (GROUP BY 1, 2) Works but very bad practice Always use column names β€” safer & readable
Performance on large tables Slow without index on GROUP BY columns Index the grouping columns + frequently filtered columns
GROUP BY + JOIN Aggregates after join β€” careful with duplication Use subquery / CTE if join causes row multiplication

5. Quick cheat-sheet (keep in your notes)

Goal Typical GROUP BY pattern HAVING example
Count per category GROUP BY city HAVING COUNT(*) > 10
Average / total per group GROUP BY enrollment_year HAVING AVG(gpa) >= 8.5
Multiple grouping levels GROUP BY city, fees_paid HAVING COUNT(*) >= 2
Filter groups after aggregation GROUP BY … HAVING … β€”
Get list of values per group GROUP BY city, STRING_AGG(name, ‘, ‘) β€”

Your mini homework right now

  1. Calculate number of students + average GPA per city
  2. Same query but only show cities with average GPA β‰₯ 9.0 (use HAVING)
  3. Group by enrollment_year and fees_paid β€” show count & avg GPA per combination
  4. Try the wrong query (SELECT city, COUNT(*) without GROUP BY) β†’ see the error

Next class?

Tell me:

  • Want HAVING vs WHERE deep comparison?
  • GROUP BY with JOIN (common real-world pattern)?
  • Advanced grouping: GROUPING SETS, ROLLUP, CUBE?
  • Aggregates inside window functions (no GROUP BY needed)?

Your guru is ready β€” what’s the next topic? πŸš€

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *