Lesson 4 of 4

Progress: 0/3 exercises solved (0%)

← PreviousFinal lesson

Solve all exercises below to unlock the next lesson.

Chained CTEs — multiple WITH clauses

Lesson Description

Break complex logic into clear SQL steps so your queries are easier to debug, explain, and scale.

Easy Project

Mini project: Build a 3-step CTE pipeline that isolates top customers, calculates spend metrics, and returns a clean final view.

You can define several CTEs in one WITH block, separated by commas. Each CTE can reference the ones defined before it.

Syntax

WITH
  cte_one AS (
    SELECT ...
  ),
  cte_two AS (
    SELECT ... FROM cte_one WHERE ...
  )
SELECT *
FROM cte_two;

Why chain CTEs?

  • Readability: split a complex query into clearly named steps.
  • De-duplication: define expensive sub-results once and reference them multiple times.
  • Debugging: temporarily SELECT * FROM cte_name to inspect intermediate results.

Example: top departments by average salary

WITH
  dept_stats AS (
    SELECT
      department_id,
      AVG(salary)  AS avg_salary,
      COUNT(*)     AS headcount
    FROM employees
    GROUP BY department_id
  ),
  ranked AS (
    SELECT *,
      RANK() OVER (ORDER BY avg_salary DESC) AS rnk
    FROM dept_stats
  )
SELECT d.name, r.avg_salary, r.headcount
FROM ranked r
JOIN departments d ON d.id = r.department_id
WHERE r.rnk <= 3
ORDER BY r.rnk;

Referencing a CTE multiple times

WITH monthly_revenue AS (
  SELECT DATE_TRUNC('month', order_date) AS month,
         SUM(oi.quantity * oi.unit_price) AS revenue
  FROM orders o
  JOIN order_items oi ON oi.order_id = o.id
  GROUP BY 1
)
SELECT
  month,
  revenue,
  LAG(revenue) OVER (ORDER BY month) AS prev_month,
  revenue - LAG(revenue) OVER (ORDER BY month) AS change
FROM monthly_revenue
ORDER BY month;

Tips

  • Name CTEs after what they represent (dept_stats, top_products) not after steps (step1, temp).
  • In PostgreSQL, CTEs may be inlined (optimized away) unless you write AS MATERIALIZED (...).
  • There is no practical limit on the number of CTEs in a single query.

Learning context

This lesson is part of Subqueries & CTEs. Focus on the core idea in Chained CTEs — multiple WITH clauses, 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: Chained CTEs — multiple WITH clauses

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

Exercise 1

Department salary ranking with two CTEs

Enterprise Workforce Analyticseasy

Write two CTEs: dept_stats (avg salary and headcount per department) and ranked_depts (rank departments by avg salary descending). Return department name, avg_salary, and emp_count for all departments, ordered by rank.

Run a query to see results here.
Exercise 2

Top 3 product categories by revenue (two CTEs)

Commerce Operations Intelligenceeasy

Use two CTEs: category_revenue (total revenue per category from order_items + products) and ranked_cats (rank by revenue descending). Return the top 3 category name and revenue, ordered by rank.

Run a query to see results here.
Exercise 3

Top 5 doctors by appointment count (two CTEs)

Clinical Care Performanceeasy

Use two CTEs: doc_stats (appointment count per doctor) and ranked_docs (rank doctors by appointment count descending). Return the top 5 doctor first_name, last_name, and total_appointments, ordered by rank.

Run a query to see results here.

Final checkpoint

End-of-course high-level quiz

Pass mark: 80%. Review each explanation after you submit.

1. Which clause should you use to filter grouped results?

2. What is the safest way to avoid accidental row multiplication in joins?

3. Which feature is best for ranking rows within partitions?

4. Why should final analytical queries usually include ORDER BY?

5. When query logic gets complex, what improves readability most?

Lesson 4 of 4

0/3 solved (0%)

← PreviousFinal lesson

Finish this lesson to unlock next.