Module 2: Aggregating & Grouping Data35 min

Combining Aggregation Techniques

Progress Tracking

Log in to save this lesson and continue from where you left off.

Log in

Putting It All Together

You’ve learned the pieces: aggregate functions, GROUP BY, HAVING, NULL handling, conditional aggregation. Real analysis usually requires combining several of these in one query.

Let’s walk through building a complex query step by step.

Building Queries Incrementally

Here’s a business question: Find departments with more than 2 employees hired after 2022, showing their headcount and average salary, sorted by average salary.

Don’t need to write it all at once. Build it piece by piece, testing after each step.

Headcount by Department

Table: techcorp_workforce
idfirst_namelast_namedepartmentsalaryphone_numberjoining_date
1SarahMitchellHR95000555-01012021-03-15
2MichaelChenHR88000555-01022022-06-01
3EmilyRodriguezHR825002021-09-20
4DavidParkHR80000555-01042023-01-10
5LisaThompsonHR650002021-04-05
1
Count Employees by Department

Count how many employees are in each department.

Tables: techcorp_workforce

Run it. Check the output makes sense before moving to the next step.

Step 2: Only Hires After 2022

Now add the row-level filter.

Oracle doesn’t implicitly cast string literals to dates — use a DATE literal or TO_DATE(). The other three dialects accept the plain string format directly.

2
Filter to Recent Hires

Add a WHERE clause to keep only employees who joined after 2022-01-01.

Tables: techcorp_workforce

Now you’re only counting recent hires. Check that the numbers changed.

Step 3: Departments with More Than 2 Such Hires

3
Add a HAVING Filter

Add HAVING to keep only departments with more than 2 employees.

Tables: techcorp_workforce

Only departments meeting the threshold show up now.

Step 4: Add Salary Stats and Sort

4
Complete the Analysis

Add average, minimum, and maximum salary columns and sort by average salary descending.

Tables: techcorp_workforce

Now you’ve answered the full business question. Each step was testable on its own.

Build incrementally

Always build queries incrementally. Run after each change. It’s much easier to fix a bug in the step you just added than to debug a 20-line query that doesn’t work.

Combining GROUP BY with Conditional Aggregation

You can use CASE WHEN inside grouped queries for detailed breakdowns:

SQL
SELECT
  department,
  COUNT(*) AS total,
  SUM(CASE WHEN salary < 80000 THEN 1 ELSE 0 END) AS under_80k,
  SUM(CASE WHEN salary >= 80000 THEN 1 ELSE 0 END) AS over_80k,
  ROUND(AVG(salary), 0) AS avg_salary
FROM techcorp_workforce
GROUP BY department
ORDER BY total DESC;

Each department row now shows the salary distribution within that department.

Table: playbook_users
user_idcreated_atcompany_idlanguageactivated_atstate
112013-01-01 04:41:131german2013-01-01active
522013-01-05 15:30:452866spanish2013-01-05active
522013-01-05 15:30:452866german2013-01-05active
1082013-01-10 11:04:581848spanish2013-01-10active
1672013-01-16 20:40:246709arabic2013-01-16active
5
Find Companies with Chinese Speakers

Find companies with 2 or more Chinese-speaking users. Use WHERE, GROUP BY, HAVING, and ORDER BY together.

Tables: playbook_users

The Query Building Checklist

When writing complex aggregation queries, follow this order:

  1. Start with SELECT and FROM
  2. Add WHERE if you need to filter individual rows
  3. Add GROUP BY with the columns you want to segment by
  4. Add HAVING if you need to filter based on aggregate values
  5. Add ORDER BY to sort your results
  6. Test after each step

Top 10 Songs 2010

Filter by year with WHERE, group appropriately, then use ORDER BY and LIMIT.

Table: billboard_top_100_year_end
yearyear_rankgroup_nameartistsong_nameid
19561Elvis PresleyElvis PresleyHeartbreak Hotel1
19562Elvis PresleyElvis PresleyDon't Be Cruel2
19563Nelson RiddleNelson RiddleLisbon Antigua3
19564PlattersPlattersMy Prayer4
19565Gogi GrantGogi GrantThe Wayward Wind5
6
Top 10 Songs 2010
View solution

Find the top 10 ranked songs in 2010. Output the rank, group name, and song name, but do not show the same song twice. Sort the result based on the rank in ascending order.

Tables: billboard_top_100_year_end

Department Workforce Analysis

Filter with WHERE before grouping, then use HAVING to filter groups.

Table: techcorp_workforce
idfirst_namelast_namedepartmentsalaryphone_numberjoining_date
1SarahMitchellHR95000555-01012021-03-15
2MichaelChenHR88000555-01022022-06-01
3EmilyRodriguezHR825002021-09-20
4DavidParkHR80000555-01042023-01-10
5LisaThompsonHR650002021-04-05
7
Department Workforce Analysis
View solution

The workforce planning team is analyzing department growth since the company's expansion, focusing on teams that have grown substantially. For each department with 5 or more employees hired after 2020, return the `name`, `headcount`, `total payroll`, and `average salary`.

Tables: techcorp_workforce

Key Takeaways

You now have a complete toolkit for summarizing and analyzing data:

  • COUNT, SUM, AVG, MIN, MAX for basic aggregation
  • GROUP BY to segment your data
  • HAVING to filter aggregated results
  • Understanding of how NULLs behave in aggregates
  • CASE WHEN for conditional aggregation and pivots
  • The ability to combine all these techniques

What’s Next

So far, all your queries have worked with a single table. But real databases have data spread across multiple tables: customers in one, orders in another, products in a third. Module 3 introduces JOINs, which let you combine data from multiple tables. That’s when things get really powerful.