Skip to content
    SeaCode
    Learning tracksCode ArenaWorkshops & EventsInstructors
    Log inSign up
    SQLSQL

    First questions to the data

    • What are SQL and databases?
    • SELECT: choosing columns
    • WHERE: filtering rows
    • ORDER BY and LIMIT: sort and take the top

    Summarizing and grouping

    • Aggregates: COUNT, SUM, AVG
    • GROUP BY and HAVING
    • CASE, COALESCE and text functions

    Joining tables

    • Keys and relationships
    • INNER JOIN
    • LEFT JOIN: leave nobody out
    • Three-table joins and self joins
    • Subqueries and CTEs

    Building tables and changing data

    • CREATE TABLE and constraints
    • INSERT, UPDATE and DELETE
    • Transactions: all or nothing
    • SQL injection: the most dangerous mistake

    Professional level

    • Indexes: why is my query slow?
    • Window functions: rankings and totals without losing rows
    • Designing tables: normalization
    • Project: analytics for a learning platform
    SQL

    Summarizing and grouping · Lesson 6 of 20

    GROUP BY and HAVING

    One number per group, and filtering the groups themselves.

    10 minutes2 games

    COUNT(*) alone gives one number for the whole table. To answer "how many students in each city?" you need GROUP BY: it splits rows into groups by a column's value, and the aggregate runs on each group separately.

    SQL
    SELECT city, COUNT(*) AS students, MAX(xp) AS best_xp
    FROM students
    GROUP BY city
    ORDER BY students DESC, city;

    8 rows

    Split: Cairo (3), Alexandria (2), Giza (2), Mansoura (1)

    COUNT and MAX per group

    4 rows in the result

    HAVING: filtering after grouping

    WHERE filters rows before grouping, so it can't use COUNT. To filter the groups themselves (cities with more than one student) use HAVING.

    Step by step1 / 6
    1. 1SELECT city, COUNT(*) AS students
    2. ▶FROM students
    3. 3WHERE xp IS NOT NULL
    4. 4GROUP BY city
    5. 5HAVING COUNT(*) > 1
    6. 6ORDER BY city;

    Variables

    rows8

    Output

    …

    Take every student.

    The real execution order: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.

    Important

    Every column in SELECT must be in GROUP BY or inside an aggregate. PostgreSQL rejects queries that break this rule, but SQLite and older MySQL may accept them and return a value from an arbitrary row in the group, a subtle bug.

    Spot the bug

    This query raises an error. Which line?

    Interview question

    What's the difference between WHERE and HAVING?

    Exercise

    For each track in courses: the number of courses as courses and the average price as avg_price, ordered by track.

    Expected result:
    track | courses | avg_price
    data | 2 | 350
    systems | 1 | 500
    web | 3 | 350
    SQL
    SELECT track
    FROM courses;

    Learn more from

    • PostgreSQL docs: GROUP BY and HAVINGpostgresql.org
    • PostgreSQL docs: Aggregate functions tutorialpostgresql.org
    • SQLite: SELECT (GROUP BY and HAVING)sqlite.org

    Played 0 of 2 games

    Sign in to save your progress and earn XP.

    PreviousAggregates: COUNT, SUM, AVGNextCASE, COALESCE and text functions
    SeaCode

    Learn to code for real, online or at our branch in front of Cairo University, Giza.

    Learn

    • All courses
    • Interactive tutorials
    • Interview practice problems
    • Mock interview
    • Learning tracks
    • Code Arena
    • Workshops & Events
    • Knowledge library
    • Team projects

    Your account

    • Log in
    • Sign up
    • Learning plan
    • Certificates
    • Site map

    Contact us

    • WhatsApp
    • 010 9094 1104
    • In front of Cairo University, Giza

    © 2026 SeaCode. All rights reserved.