runtime
49 / 88

lesson 49 Advanced product analysis · advanced

Capstone: customer insights

Bring filtering, joins and aggregation together for customer analysis.

the idea

Combine filtering, joins, aggregation and ranking to answer a business question. First compute each customer's paid revenue, then rank those customer totals. Write one stage at a time.

tables in this lesson

The challenges use this data. Each column shows its type underneath; → marks a link to another table.

customers4 columns · 8 rows
idinteger · keynametextcitytextjoined_attext
1AliceChicago2024-01-10
2BenAustin2024-02-12
3CaraSeattle2024-03-05
4DevChicago2024-04-20
5ElenaNULL2024-05-01

showing 5 of 8 rows

products4 columns · 6 rows
idinteger · keynametextcategorytextpricereal
1NotebookStationery12
2Desk lampHome45
3KeyboardTech80
4Pen setStationery8
5HeadphonesTech120

showing 5 of 6 rows

orders6 columns · 12 rows
idinteger · keycustomer_idintegerproduct_idintegerquantityintegerstatustextordered_attext
101112paid2025-01-01
102231paid2025-01-02
103121paid2025-01-05
104352pending2025-01-08
105445paid2025-02-01

showing 5 of 12 rows

example

The idea in one query. Press Run to see what it returns; running examples never affects your progress.

example.sql
WITH revenue AS (
  SELECT c.name,SUM(o.quantity*p.price) AS paid_revenue
  FROM customers c
  JOIN orders o ON o.customer_id=c.id
  JOIN products p ON p.id=o.product_id
  WHERE o.status='paid'
  GROUP BY c.id,c.name
)
SELECT
  name,
  paid_revenue,
  DENSE_RANK() OVER(ORDER BY paid_revenue DESC) AS revenue_rank
FROM revenue;

Watch for: Rank customer totals, not individual order amounts.

build it step by step

Each step changes one thing. Run them in order and watch the result change.

  1. Assemble paid revenue pieces. Customer insights join customers, paid orders, and product prices before summing. Check the join keys first.

    step-1.sql
    SELECT c.name, o.quantity, p.price, o.status
    FROM customers c
    JOIN orders o ON o.customer_id = c.id
    JOIN products p ON p.id = o.product_id
    WHERE o.status = 'paid'
    LIMIT 8;
  2. Summarize paid revenue per customer. The capstone CTE pattern computes paid_revenue, then the outer query ranks or filters those totals.

    step-2.sql
    WITH revenue AS (
      SELECT c.name, SUM(o.quantity * p.price) AS paid_revenue
      FROM customers c
      JOIN orders o ON o.customer_id = c.id
      JOIN products p ON p.id = o.product_id
      WHERE o.status = 'paid'
      GROUP BY c.name
    )
    SELECT name, paid_revenue
    FROM revenue
    ORDER BY paid_revenue DESC;

challenge 1

Show name, paid_revenue and revenue_rank for customers with paid orders. Use DENSE_RANK, highest revenue first in the rank calculation.

Return namepaid_revenuerevenue_rankany row order

challenge-1.sql
 
To master this lesson, solve both challenges without hints and pass the concept check. 3 of 3 to go.