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.
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.
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.
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;
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.
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%';
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.
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.
SELECT sub_id, customer_id, cancel_date FROM subscriptions WHERE cancel_date IS NOT NULL;
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;
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.
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%';
Try it yourself - this week ◐ 20-30 min total
- Re-run the Part 1 trend query, but change the status filter to include refunded orders. Note how the March number shifts, and write one sentence on why the honest version excludes them.
- Pick a different month (say May) and run the full funnel on it: confirm, drill by status, check events. Is there a story, or is it a quiet month?
- Write a three-sentence brief for your chosen month, one claim per sentence, each naming the query that backs it.
- Extend Part 3: join
subscriptionstocustomersso your churned-subscriber finding includes the customer's name and plan. - Bring one question to b10: your March queries feel instant on 33 orders - what happens when the table has 33 million rows? Next session is exactly that.
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:
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.