ποΈ SQL Β· Topic 7 of 20
GROUP BY & HAVING β SQL Questions with Answers
30 practice questions on GROUP BY & HAVING, each with the correct answer and a clear explanation of why it is right. Read through them as revision notes, or take this topic as an interactive quiz to test yourself.
1 easy Β· 16 medium Β· 13 hard Β· Part of SQL: Databases from basics to window functions - 20 topics.
Medium questions (16)
Q2. medium
Which columns may appear in SELECT alongside GROUP BY?
- A Only the grouped columns and aggregate functions
- B Any column
- C Only aggregates
- D Only the first column
Answer: A β Only the grouped columns and aggregate functions
Every other column would have many possible values per group, so the database cannot pick one. Group by it, or aggregate it with MAX/MIN.
GROUP BYRules
Q4. medium
What does HAVING do?
SELECT city, COUNT(*) AS n
FROM customers
WHERE active = 1 -- rows
GROUP BY city
HAVING COUNT(*) > 10; -- groups
- A Filters the GROUPS after aggregation - it can use aggregate functions
- B Filters rows before grouping
- C Sorts groups
- D Is the same as WHERE
Answer: A β Filters the GROUPS after aggregation - it can use aggregate functions
WHERE filters raw rows first; HAVING then filters the summarised groups. Both can appear in one query.
HAVINGWHERE
Q6. medium
Which is more efficient for filtering rows that will never be needed?
- A WHERE - it removes rows BEFORE the expensive grouping
- B HAVING - it filters at the end
- C They are identical
- D Neither
Answer: A β WHERE - it removes rows BEFORE the expensive grouping
Filter as early as possible. Reserve HAVING for conditions that genuinely depend on aggregated values.
PerformanceWHERE
Q7. medium
Can you GROUP BY several columns?
- A Yes - it groups by each unique COMBINATION of those columns
- B No, only one column
- C Only with a JOIN
- D Only two columns maximum
Answer: A β Yes - it groups by each unique COMBINATION of those columns
GROUP BY country, city produces one row per country+city pair - the standard way to build multi-level summaries.
GROUP BYMultiple columns
Q8. medium
What does this produce?
SELECT dept, COUNT(*) FROM employees GROUP BY dept ORDER BY COUNT(*) DESC;
- A Departments listed from largest to smallest headcount
- B Departments in alphabetical order
- C An error - you cannot ORDER BY an aggregate
- D One row
Answer: A β Departments listed from largest to smallest headcount
ORDER BY runs after aggregation, so it can sort by aggregate values (or by their alias). This is the classic 'top categories' report.
ORDER BYAggregates
Q10. medium
Can HAVING be used without GROUP BY?
- A Yes - the whole result is treated as one group
- B No, GROUP BY is mandatory
- C Only with COUNT
- D It is always an error
Answer: A β Yes - the whole result is treated as one group
SELECT COUNT(*) FROM t HAVING COUNT(*) > 100 returns the count only if it exceeds 100. Rare, but valid.
HAVING
Q12. medium
What does this answer?
SELECT customer_id, SUM(total) FROM orders GROUP BY customer_id HAVING SUM(total) > 10000;
- A Which customers have spent more than 10,000 in total
- B Which single orders exceed 10,000
- C All customers
- D An error
Answer: A β Which customers have spent more than 10,000 in total
The condition applies to the SUM per customer, not to individual orders. Using WHERE total > 10000 would ask a different question entirely.
HAVINGBusiness queries
Q14. medium
How would you count orders per month?
SELECT DATE_TRUNC('month', order_date) AS month, COUNT(*)
FROM orders GROUP BY 1 ORDER BY 1;
- A GROUP BY a date expression such as DATE_TRUNC('month', order_date) or EXTRACT(MONTH FROM order_date)
- B GROUP BY order_date
- C GROUP BY month
- D It is impossible
Answer: A β GROUP BY a date expression such as DATE_TRUNC('month', order_date) or EXTRACT(MONTH FROM order_date)
Grouping by the raw timestamp would create a group per second. Truncating to the month collapses them correctly. Include the year, or January 2025 and January 2026 merge.
DatesDATE_TRUNC
Q16. medium
How many rows does GROUP BY return?
- A One row per unique group
- B The same as the original table
- C Always one
- D Twice the groups
Answer: A β One row per unique group
Ten cities produce ten rows. This 'collapse' is why non-grouped, non-aggregated columns are not allowed.
GROUP BY
Q19. medium
Which query finds departments with an average salary above 50000?
- A SELECT dept, AVG(salary) FROM emp GROUP BY dept HAVING AVG(salary) > 50000;
- B SELECT dept FROM emp WHERE AVG(salary) > 50000;
- C SELECT dept, AVG(salary) FROM emp WHERE salary > 50000;
- D SELECT AVG(dept) FROM emp;
Answer: A β SELECT dept, AVG(salary) FROM emp GROUP BY dept HAVING AVG(salary) > 50000;
Option B is invalid (aggregate in WHERE). Option C is a different question - it averages only the high salaries, ignoring low earners.
HAVINGAVG
Q21. medium
What does this find?
SELECT product_id FROM order_items GROUP BY product_id HAVING COUNT(DISTINCT order_id) >= 3;
- A Products appearing in at least 3 different orders
- B Products ordered 3 times total
- C The three most popular products
- D An error
Answer: A β Products appearing in at least 3 different orders
COUNT(DISTINCT order_id) counts distinct orders, not line items - so a product bought 3 times in ONE order would not qualify. Precision matters in metrics.
COUNT DISTINCTHAVING
Q23. medium
How do you show groups WITHOUT the aggregate column?
- A Just omit it from SELECT - GROUP BY still works: SELECT city FROM t GROUP BY city;
- B It is required in SELECT
- C Use DISTINCT instead only
- D Not possible
Answer: A β Just omit it from SELECT - GROUP BY still works: SELECT city FROM t GROUP BY city;
That query is effectively SELECT DISTINCT city. GROUP BY without aggregates is legal, though DISTINCT states the intent more clearly.
DISTINCTGROUP BY
Q25. medium
Which finds cities with exactly one customer?
- A GROUP BY city HAVING COUNT(*) = 1
- B WHERE COUNT(*) = 1
- C GROUP BY city LIMIT 1
- D SELECT DISTINCT city
Answer: A β GROUP BY city HAVING COUNT(*) = 1
HAVING can test for any count - equal to, greater than, or a range. Useful for finding one-off or anomalous values.
HAVING
Q27. medium
How do you get the top 3 categories by revenue?
- A GROUP BY category, ORDER BY SUM(revenue) DESC, LIMIT 3
- B HAVING TOP 3
- C GROUP BY category LIMIT 3
- D MAX(revenue, 3)
Answer: A β GROUP BY category, ORDER BY SUM(revenue) DESC, LIMIT 3
Aggregate, sort by the aggregate, then limit. Option C would return three arbitrary categories because LIMIT applies before any sorting is specified.
Top NORDER BY
Q29. medium
Which clause would you add to only show groups with no NULL values in a column?
- A HAVING COUNT(col) = COUNT(*)
- B WHERE col IS NOT NULL only
- C HAVING col IS NOT NULL
- D It is impossible
Answer: A β HAVING COUNT(col) = COUNT(*)
COUNT(col) skips NULLs, so equality with COUNT(*) means the group is complete. A neat data-quality check - option B would instead remove the NULL rows before grouping.
COUNTData quality
Q30. medium
Can you combine WHERE, GROUP BY, HAVING and ORDER BY in one query?
SELECT city, COUNT(*) AS n
FROM customers
WHERE active = 1
GROUP BY city
HAVING COUNT(*) > 5
ORDER BY n DESC;
- A Yes - in that exact order: WHERE (rows), GROUP BY (group), HAVING (groups), ORDER BY (sort)
- B No, only one filter is allowed
- C HAVING must come before GROUP BY
- D ORDER BY must come first
Answer: A β Yes - in that exact order: WHERE (rows), GROUP BY (group), HAVING (groups), ORDER BY (sort)
A full aggregate query commonly uses all four. Written order is fixed; the database executes them as WHERE, GROUP BY, HAVING, then ORDER BY - which is why each clause can only reference what already exists at its stage.
Clause orderExecution order
Hard questions (13)
Q3. hard
Why does this fail in most databases?
SELECT city, name, COUNT(*) FROM customers GROUP BY city;
- A name is neither grouped nor aggregated - each city has many names
- B COUNT cannot be used with GROUP BY
- C city must be aggregated
- D It always works
Answer: A β name is neither grouped nor aggregated - each city has many names
Add name to GROUP BY (giving one row per city+name), or aggregate it: MAX(name). MySQL historically allowed this and returned an arbitrary name - a source of silently wrong reports.
GROUP BYONLY_FULL_GROUP_BY
Q5. hard
In what ORDER does the database process these clauses?
- A FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT
- B SELECT, FROM, WHERE, GROUP BY
- C GROUP BY, WHERE, SELECT
- D The order they are written
Answer: A β FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT
This single fact explains most GROUP BY rules: WHERE cannot see aggregates (they do not exist yet), and SELECT aliases are unavailable to WHERE, GROUP BY and HAVING - but ARE available to ORDER BY.
Execution order
Q9. hard
How does GROUP BY treat NULL values?
- A All NULLs form ONE group together
- B Each NULL becomes its own group
- C NULL rows are excluded
- D It errors
Answer: A β All NULLs form ONE group together
Even though NULL = NULL is not TRUE in comparisons, grouping and DISTINCT treat NULLs as the same value. Your report will show a single NULL row.
NULLGROUP BY
Q11. hard
Which query finds duplicate emails?
- A SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1;
- B SELECT DISTINCT email FROM users;
- C SELECT email FROM users WHERE COUNT(*) > 1;
- D SELECT COUNT(email) FROM users;
Answer: A β SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1;
Group by the column and keep groups appearing more than once - the canonical duplicate-finding query, and a common interview question.
DuplicatesHAVING
Q13. hard
Can you use a column ALIAS in GROUP BY?
- A It depends - MySQL and PostgreSQL allow it, but the standard (and SQL Server) require the full expression
- B Always yes
- C Never
- D Only for numbers
Answer: A β It depends - MySQL and PostgreSQL allow it, but the standard (and SQL Server) require the full expression
For portable code, repeat the expression in GROUP BY or wrap the query in a subquery. Aliases are always safe in ORDER BY.
AliasesDialects
Q15. hard
What does GROUP BY 1 mean?
- A Group by the FIRST column in the SELECT list (positional reference)
- B Group into one group
- C Group by the number 1
- D A syntax error
Answer: A β Group by the FIRST column in the SELECT list (positional reference)
Convenient shorthand for long expressions, common in analytics. The risk is that reordering SELECT silently changes the grouping.
Positional grouping
Q17. hard
What is the difference between these two?
A) WHERE status='paid' GROUP BY city
B) GROUP BY city HAVING MIN(status)='paid'
- A A counts only paid rows per city; B keeps cities where a condition holds across the whole group
- B They are identical
- C B is invalid
- D A is invalid
Answer: A β A counts only paid rows per city; B keeps cities where a condition holds across the whole group
WHERE changes which rows enter each group; HAVING decides which finished groups survive. Mixing them up changes the meaning of a report entirely.
WHERE vs HAVING
Q18. hard
What does GROUP BY ROLLUP(country, city) add?
SELECT country, city, SUM(sales)
FROM t GROUP BY ROLLUP(country, city);
- A Subtotal rows per country plus a grand total, alongside the detail rows
- B Sorting by country
- C Nothing extra
- D It removes duplicates
Answer: A β Subtotal rows per country plus a grand total, alongside the detail rows
ROLLUP generates hierarchical subtotals - very useful for financial reports. The subtotal rows show NULL in the columns they aggregate over.
ROLLUPCUBEReporting
Q20. hard
Can HAVING reference a column NOT in GROUP BY or an aggregate?
- A No - HAVING can only use grouped columns and aggregates
- B Yes, any column
- C Only text columns
- D Only with a subquery
Answer: A β No - HAVING can only use grouped columns and aggregates
After grouping, individual row values no longer exist. Conditions on raw values belong in WHERE.
HAVINGRules
Q22. hard
Why might GROUP BY be slow, and what helps?
- A It must sort or hash all rows - an index on the grouped column, and filtering first with WHERE, both help
- B It is never slow
- C Only more RAM helps
- D Removing SELECT helps
Answer: A β It must sort or hash all rows - an index on the grouped column, and filtering first with WHERE, both help
Grouping a million rows requires organising them all. Reducing the input with WHERE and supporting the grouping with an index are the main levers.
PerformanceIndexes
Q24. hard
What does FILTER (WHERE ...) do on an aggregate?
SELECT
COUNT(*) AS total,
COUNT(*) FILTER (WHERE status='paid') AS paid
FROM orders;
- A Applies a condition to that ONE aggregate only - a cleaner alternative to CASE inside aggregates
- B Filters the whole query
- C Sorts the aggregate
- D Is invalid SQL
Answer: A β Applies a condition to that ONE aggregate only - a cleaner alternative to CASE inside aggregates
Standard SQL, supported by PostgreSQL and SQLite. Elsewhere use SUM(CASE WHEN ... THEN 1 ELSE 0 END).
FILTERConditional aggregation
Q26. hard
What is the risk of GROUP BY after a one-to-many JOIN?
- A Parent values are duplicated by the join, so SUM/COUNT on them is inflated
- B GROUP BY cannot follow a join
- C It removes NULLs
- D There is no risk
Answer: A β Parent values are duplicated by the join, so SUM/COUNT on them is inflated
Joining customers to orders repeats each customer per order. COUNT(*) then counts orders, not customers - use COUNT(DISTINCT customer_id) or aggregate before joining.
JoinsFan-out
Q28. hard
What does GROUP BY GROUPING SETS give you?
- A Several different groupings computed in ONE query - e.g. by country, by city, and overall
- B Only one grouping
- C A sorted output
- D A join
Answer: A β Several different groupings computed in ONE query - e.g. by country, by city, and overall
It avoids running three separate queries and UNIONing them. ROLLUP and CUBE are convenient shorthands for common grouping sets.
GROUPING SETSROLLUPCUBE