Lesson 2 of 4

Progress: 0/3 exercises solved (0%)

← Previous

Solve all exercises below to unlock the next lesson.

Common Table Expressions (WITH)

Lesson Description

Name a subquery so you can read top-to-bottom.

Easy Project

Mini project: Turn this lesson into a real-world query artifact by writing one clean business report query and validating output quality.

A CTE defines a named, temporary result set that you can reference in the main query — like a view that lives only for the duration of the query.

Syntax

WITH cte_name AS (
  SELECT ...
)
SELECT *
FROM cte_name
WHERE ...;

Example: top customers by spend

WITH customer_spend AS (
  SELECT
    o.customer_id,
    SUM(oi.quantity * oi.unit_price) AS total_spent
  FROM orders o
  JOIN order_items oi ON oi.order_id = o.id
  GROUP BY o.customer_id
)
SELECT
  c.first_name,
  c.last_name,
  cs.total_spent
FROM customer_spend cs
JOIN customers c ON c.id = cs.customer_id
ORDER BY cs.total_spent DESC
LIMIT 10;

Multiple CTEs

Separate them with a comma. Each CTE can reference the ones before it:

WITH
  dept_stats AS (
    SELECT department_id, AVG(salary) AS avg_sal
    FROM employees
    GROUP BY department_id
  ),
  top_depts AS (
    SELECT * FROM dept_stats WHERE avg_sal > 9000
  )
SELECT d.name, td.avg_sal
FROM top_depts td
JOIN departments d ON d.id = td.department_id;

CTE vs subquery

CTESubquery
NamedYesNo
Reusable in same queryYesNo
ReadableVeryCan get nested/messy

Tips

  • Name CTEs after what they represent (customer_spend, dept_stats) not what they do (step1, temp).
  • In PostgreSQL, CTEs are not materialized by default (the optimizer may inline them). Use AS MATERIALIZED (...) to force it.
  • Recursive CTEs (WITH RECURSIVE) can traverse tree structures like org charts.

Learning context

This lesson is part of Subqueries & CTEs. Focus on the core idea in Common Table Expressions (WITH), then validate with deliberate practice.

What to master

  • Understand clause order and intent
  • Write deterministic result queries
  • Use clear aliases and readable structure

Common mistakes

  • Skipping ORDER BY in final outputs
  • Using joins before validating base rows
  • Not checking row counts after changes

High-level strategy

  • Start simple, then layer complexity
  • Run often and compare expected shape
  • Refactor with CTEs when logic grows

Task ladder

  1. Baseline query: get a correct first output.
  2. Add one complication: edge case, join, filter, or ranking rule.
  3. Re-run and refine until output is stable and explainable.

Transparent data checks

  • Check row count before and after each major clause.
  • Validate one manual sample row for correctness.
  • Confirm final ordering and column naming for trust.

Retention loop

  • Run the solution once.
  • Rewrite from memory with one variation.
  • Explain the logic in plain English in one sentence.

Logical reasoning for commands

WHERE

Why: Limits rows to only the business-relevant subset.

Memory cue: Filter early to reduce noise.

ORDER BY

Why: Makes output deterministic and reviewable.

Memory cue: No ORDER BY means no guaranteed row order.

AS alias

Why: Makes output columns readable for teams and reports.

Memory cue: If the name is clear, the query is easier to trust.

Concept check

Quick check: Common Table Expressions (WITH)

3 quick questions. One at a time. Instant score at the end.

Exercise 1

Top 5 customers by total spend

Commerce Operations Intelligencehard

Using a CTE, return the first_name, last_name, and total_spent of the top 5 customers by total order-item value (quantity * unit_price). Order by total_spent descending.

Run a query to see results here.
Exercise 2

Department salary stats with a CTE

Enterprise Workforce Analyticseasy

Use a CTE named dept_stats to compute avg_salary and emp_count per department_id. Then return all columns from dept_stats ordered by avg_salary descending.

Run a query to see results here.
Exercise 3

Top 3 departments by appointment volume

Clinical Care Performanceeasy

Use a CTE to count appointments per doctor, then join to departments. Return the top 3 department name values and their total appt_count, ordered by appt_count descending.

Run a query to see results here.

Lesson 2 of 4

0/3 solved (0%)

← Previous

Finish this lesson to unlock next.