Lesson Description
Break complex logic into clear SQL steps so your queries are easier to debug, explain, and scale.
Lesson 4 of 4
Progress: 0/3 exercises solved (0%)
Solve all exercises below to unlock the next lesson.
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.
WITH
cte_one AS (
SELECT ...
),
cte_two AS (
SELECT ... FROM cte_one WHERE ...
)
SELECT *
FROM cte_two;
SELECT * FROM cte_name to inspect intermediate results.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;
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;
dept_stats, top_products) not after steps (step1, temp).AS MATERIALIZED (...).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
Common mistakes
High-level strategy
Task ladder
Transparent data checks
Retention loop
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
3 quick questions. One at a time. Instant score at the end.
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.
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.
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.
Final checkpoint
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%)
Finish this lesson to unlock next.