learn-sql-with-phoebe / Builder session 9 of 10
Learn SQL with Phoebe · Builder track · Session 9 of 10

Analyst case study: the March revenue drop

Daybreak's founder walks in with one sentence: "Revenue fell in March - why?" No hint, no dashboard, just a question and a database. This is the session where the last eight click into one skill. You will confirm the drop, drill into what changed, hunt for causes in customer behavior, and write the one-paragraph brief a founder can actually act on. Every query runs live against Daybreak, and every claim in your brief will be backed by a query you can point to.

🔴 Builder track Practitioners: analysts · DE · DS · PMs Runs in your browser · SQLite Everything from b1-b7
0-5 · The founder's question 5-20 · Confirm & drill 20-38 · Causes & cohorts 38-45 · Write the brief
Part 0

Think like an analyst, not a query-writer

Anyone can write SQL. An analyst decides which SQL to write, in what order, and knows when to stop. The trap with "revenue dropped, why?" is theorizing first - blaming a campaign, a price change, a season - before you have confirmed the drop is even real and pinned down where it lives. Tonight you run the discipline instead: confirm, drill, explain, recommend. The Daybreak numbers are small enough to hold in your head, so the method stays in focus, not the arithmetic.

Live - presented in session Self-study - read after class ▶ Live SQL - editable & runnable Official sources covered
★ What you walk out with today A repeatable investigation loop you can run on any "the metric moved" question at work: confirm the trend with a clean query, drill into the affected slice, look for a behavioral cause, sanity-check with a cohort, then write a short brief where every claim cites a query. That last part is what gets an analyst trusted.
The method · your map for tonight

The investigation funnel 3 min live

Four moves, narrowing each time. You start wide (is the drop real?), narrow to the month, narrow to a behavior, then widen just enough to sanity-check - and only then do you write anything down. Skipping straight to "recommend" is how analysts get burned; the funnel keeps you honest.

1 · Confirm Is the drop real? 2 · Drill What changed in March? 3 · Explain Why did it happen? 4 · Recommend Now write the brief. Each stage is one or two queries. You never skip Confirm - theorizing before confirming is the classic mistake.
🔍 Click to zoom - the four moves of any metric-drop investigation
Part 1 · covers Mode "SQL Analytics Training" - confirm the trend

Confirm the drop 6 min live

Before any theory, get the actual monthly trend on screen. We sum completed line revenue per month, then use LAG (from b7) to show the month-over-month change in the same result. If March really dropped, the change column will show it in one negative number - no arguing with it.

LiveMonthly revenue, with the change column3 min

Line revenue is quantity * unit_price, and we count only completed orders - refunded and cancelled money is not revenue. LAG(rev) pulls the previous month's total onto the current row so you see the delta directly.

Confirm before theorizing: February to March, in one query February 271 March 150 -121 Completed revenue fell from 271 in February to 150 in March - confirmed by one query.
🔍 Click to zoom - confirm the number before you theorize about why
WITH m AS (
  SELECT substr(o.order_date,1,7) AS mo,
         SUM(oi.quantity*oi.unit_price) AS rev
  FROM orders o
  JOIN order_items oi ON o.order_id = oi.order_id
  WHERE o.status = 'completed'
  GROUP BY mo
)
SELECT mo, rev,
       rev - LAG(rev) OVER (ORDER BY mo) AS change
FROM m
ORDER BY mo;
Confirm before you theorize Notice we have not guessed a cause yet. The whole point of stage one is to replace "I heard revenue dropped" with a number you can defend: Feb 271, Mar 150, a -121 change. Now the investigation has a target.
Self-studyWhy the status filter is not optional2 min read

If you sum revenue across all orders regardless of status, you fold refunded and cancelled money into the total - and your "revenue" is now a fiction that no finance team will accept. A single refunded order can mask or fake a trend. The habit: whenever you sum money, decide explicitly which statuses count, and put it in the WHERE where a reviewer can see it. In Daybreak, completed is the honest revenue set.

  • completed - real, recognized revenue. Count it.
  • refunded - money that came back out. Exclude from revenue.
  • cancelled - never collected. Exclude.
Part 2 · drill into the affected slice

Drill into March 6 min live

The drop lives in March, so zoom in. Two cheap questions answer most of it: what statuses do March's orders have (is there a refund distorting things?), and how many orders did March even get (was it a volume problem)? Small queries, big signal.

LiveMarch orders by status3 min

Group March's orders by status. This surfaces whether a refund or cancellation is part of the story - and in Daybreak's March, one order was refunded.

SELECT status, COUNT(*) AS n
FROM orders
WHERE order_date LIKE '2026-03%'
GROUP BY status;
LiveHow many orders did March get at all?3 min

Volume is the other half. Fewer orders is a different problem from smaller orders. Count March's orders outright, then compare that mentally to the busier months.

SELECT COUNT(*) AS march_orders
FROM orders
WHERE order_date LIKE '2026-03%';
Real world

Two very different fixes. "Fewer orders" points at acquisition and retention - marketing, churn, seasonality. "Same orders, smaller baskets" points at pricing, promos, product mix. Drilling before recommending is what tells you which conversation to walk into. Guess wrong and you optimize the thing that was fine.

Part 3 · look for causes in customer behavior

Hunt for causes: events and cancellations 7 min live

Orders tell you what happened; the events and subscriptions tables hint at why. If March saw support tickets and a cancel survey, and a subscription actually cancelled that month, you have a behavioral thread that lines up with the revenue dip.

LiveWhat were customers doing in March?3 min

Count March's events by type. A cluster of support_ticket and a cancel_survey is exactly the kind of unhappy-customer signal that precedes lost revenue.

SELECT event_type, COUNT(*) AS n
FROM events
WHERE event_date LIKE '2026-03%'
GROUP BY event_type;
LiveWhich subscriptions cancelled, and when?3 min

An active subscription has a NULL cancel_date (the b2 NULL lesson pays off here). List the ones that are not NULL to see who churned - and the date tells you if it lands in March.

Three findings, read together - not yet a cause DRILL Order 1017 was refunded EXPLAIN Support tickets, cancel survey EXPLAIN Sub 2 cancelled Mar 10 These coincide with the March dip - worth reporting as correlation, not proven as the cause.
🔍 Click to zoom - three findings that coincide with March's dip, not proof of one cause
SELECT sub_id, customer_id, cancel_date
FROM subscriptions
WHERE cancel_date IS NOT NULL;
Correlation, stated honestly A cancel on March 10 and a revenue dip in March line up in time - that is worth reporting, but say it as "these coincide", not "this caused the drop". A good analyst brief is precise about what the data shows versus what it merely suggests.
Part 4 · a cohort sanity-check

Cohort peek: are we acquiring customers? 4 min live

One more angle before we write. Group customers by signup month - a "cohort" view. If new-customer intake sagged around March, that reinforces the volume story from Part 2. This is a widen-to-sanity-check move, not a new theory.

LiveNew customers by signup month3 min

substr(signup_date,1,7) gives the year-month, and grouping on it turns 15 customers into a clean intake timeline. Read it alongside the revenue trend from Part 1.

SELECT substr(signup_date,1,7) AS cohort,
       COUNT(*) AS new_customers
FROM customers
GROUP BY cohort
ORDER BY cohort;
Build-along · the deliverable

Write the "what happened in March" brief ★ 10 min · everyone writes

The queries were the easy part. The value an analyst adds is the paragraph a founder reads in 30 seconds. Rule: one claim per finding, each backed by a specific query above. No adjectives, no drama, just what the data shows and one recommendation.

Confirm. "Completed revenue fell from 271 in February to 150 in March, a -121 swing." - Part 1 query.

Drill. "March took fewer orders than its neighbours, and one order (1017) was refunded." - Part 2 queries.

Explain. "March also showed support tickets, a cancel survey, and a subscription cancellation (sub 2, Mar 10) - friction signals that coincide with the dip." - Part 3 queries.

Recommend. "Volume, not basket size, drove most of it - suggest a retention check on at-risk subscribers and a look at March acquisition." - Part 4 sanity-check.

Real world

The brief is the job. Founders and execs rarely read your SQL - they read the four sentences and decide. An analyst who hands over a clean, query-backed paragraph gets trusted with the next question; one who hands over a raw result set and says "here's the data" does not. The queries make you correct. The brief makes you useful.

SELECT SUM(oi.quantity*oi.unit_price) AS march_completed_rev
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.status = 'completed'
  AND o.order_date LIKE '2026-03%';
Homework

Try it yourself - this week ◐ 20-30 min total

Source material

Official sources covered

This session is a guided analytics investigation in the spirit of the major training curricula, run on live data instead of screenshots. It leans on every technique from b1-b7. This page covers:

Mode - SQL Analytics Training (Investigating a Drop in User Engagement)Whole session · the confirm-drill-explain investigation loop, run on Daybreak
Applies Builder sessions b1-b7SELECT, WHERE, JOIN, GROUP BY, HAVING, CTEs, and window functions (LAG) all in one case
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · A metric drops and someone asks why. What is your first step?

Confirm first. Replace "I heard it dropped" with a defensible number (Feb 271, Mar 150, -121). Only then does the hunt for a cause have a real target.

2 · Why filter on status when summing revenue?

Folding refunded or cancelled money into a revenue sum produces a number finance will reject. Summing only completed orders is the honest revenue set.

3 · What makes a good analyst brief?

One claim per finding, each traceable to a query, with correlation stated as correlation. That is what earns an analyst the next question.

Builder session 9 cheat sheet · pin this

The funnelConfirm → Drill → Explain → Recommend. Never skip Confirm; never lead with a theory.
Confirm the trendMonthly SUM(quantity*unit_price) on completed orders + LAG for the change column.
Filter status for moneyOnly completed = revenue. Refunded and cancelled distort the total - exclude them.
Drill the sliceGroup the affected month by status; count its volume. Refund vs fewer-orders are different bugs.
Causes in behaviorevents (tickets, cancel surveys) + subscriptions with cancel_date IS NOT NULL = the why.
Cohort sanity-checksubstr(signup_date,1,7) grouped = new-customer intake by month. Confirms volume stories.
Correlation ≠ causeA cancel and a dip in the same month "coincide". Say that, not "this caused it".
The brief is the jobOne claim per finding, each backed by a query. The queries make you correct; the brief makes you useful.