Hello ,
Way back in one of the earliest issues of this newsletter, I introduced the Mister Rogers Blueprint: approach any new dataset the way Mister Rogers approached a new topic on his show. With curiosity. Without assumptions. One small, friendly question at a time.
That was a while ago, and a lot of you are newer subscribers. So today, I’m going to revisit the Mister Rogers Blueprint — but this time, I want to do something different. Instead of explaining the concept, I want to show you the full process live, step by step, against a real database you haven’t seen me explore this way before.
We’ll use the Summit Adventures database (the fake adventure tourism company I created to help people learn business analytics). Even though I built it, I’m going to pretend I’m seeing it for the first time — because that’s the skill: having a repeatable process that works anywhere.
Step 1: “What’s in the Neighborhood?”
First question, every time: what tables exist and how big are they?
-- Step 1: Survey the neighborhood SELECT 'customers' AS table_name, COUNT(*) AS rows FROM customers UNION ALL SELECT 'expeditions', COUNT(*) FROM expeditions UNION ALL SELECT 'guides', COUNT(*) FROM guides UNION ALL SELECT 'expedition_instances', COUNT(*) FROM expedition_instances UNION ALL SELECT 'bookings', COUNT(*) FROM bookings UNION ALL SELECT 'payments', COUNT(*) FROM payments UNION ALL SELECT 'guide_assignments', COUNT(*) FROM guide_assignments ORDER BY rows DESC;
Results:
| Table | Rows |
|——-|——|
| payments | 2,173 |
| bookings | 1,600 |
| customers | 1,000 |
| guide_assignments | 648 |
| expedition_instances | 500 |
| expeditions | 100 |
| guides | 50 |
Already you learn things. 2,173 payments for 1,600 bookings means some bookings have multiple payments (deposits? installments?). 648 guide assignments for 500 instances means some trips have more than one guide. 100 expeditions but 500 instances means each expedition runs multiple times.
You haven’t written a single analytical query yet and you already have three hypotheses to explore.
Step 2: “What Lives Here?”
Pick the table you’re most curious about and look at a few rows:
-- Step 2: Meet the neighbors SELECT * FROM customers LIMIT 5;
What to notice:
Data types: Are dates actual dates or strings? Are IDs integers or UUIDs?
NULL patterns: Which columns have gaps?
Value ranges: Do ages look reasonable? Do emails look real?
Categorical fields: What are the distinct values in columns like `experience_level` or `country`?
-- Step 2b: What categories exist? SELECT experience_level, COUNT(*) FROM customers GROUP BY experience_level ORDER BY COUNT(*) DESC;
This tells you the vocabulary of the data. You can’t filter on values you don’t know exist.
Step 3: “How Do Things Connect?”
Now look at how tables relate:
-- Step 3: Follow the relationships
-- Start with a booking and trace it through the system
SELECT
b.booking_id,
c.first_name || ' ' || c.last_name AS customer,
e.name AS expedition,
INITCAP(e.expedition_type) AS type,
ei.start_date,
b.status AS booking_status,
COUNT(p.payment_id) AS payment_count,
COALESCE(SUM(p.amount), 0) AS total_paid
FROM bookings b
INNER JOIN customers c ON b.customer_id = c.customer_id
INNER JOIN expedition_instances ei ON b.instance_id = ei.instance_id
INNER JOIN expeditions e ON ei.expedition_id = e.expedition_id
LEFT JOIN payments p ON b.booking_id = p.booking_id
GROUP BY b.booking_id, c.first_name, c.last_name,
e.name, e.expedition_type, ei.start_date, b.status
ORDER BY b.booking_id
LIMIT 10;
This single query connects 5 tables and reveals the full data flow: Customer → Booking → Expedition Instance → Expedition, with Payments attached. You now understand the core data model.
Step 4: “What Surprises Me?”
This is where it gets interesting. Look for things that don’t match your expectations:
-- Step 4: Find the surprises
-- Bookings without payments
SELECT b.status, COUNT(*) AS bookings,
COUNT(p.payment_id) AS with_payment,
COUNT(*) - COUNT(p.payment_id) AS without_payment
FROM bookings b
LEFT JOIN payments p ON b.booking_id = p.booking_id
GROUP BY b.status;
When you find cancelled bookings that still have payments, that’s not a bug — it’s a refund process. When you find confirmed bookings with no payment, that’s worth investigating. The surprises are where the business questions live.
-- More surprises: data quality
SELECT
COUNT(*) FILTER (WHERE email NOT LIKE '%@%') AS bad_emails,
COUNT(*) FILTER (WHERE age < 10 OR age > 100) AS suspicious_ages,
COUNT(*) FILTER (WHERE phone IS NULL) AS missing_phones
FROM customers;
In real databases, you’ll always find data quality issues. Knowing they exist before you start your analysis prevents bad conclusions later.
Step 5: “What Story Does This Tell?”
Finally, ask a business question. Not a complex one — just something you’re genuinely curious about:
-- Step 5: Ask a real question
-- What types of expeditions generate the most revenue?
SELECT
INITCAP(e.expedition_type) AS type,
COUNT(DISTINCT b.booking_id) AS bookings,
'$' || TO_CHAR(SUM(p.amount)::numeric, 'FM999,999') AS revenue,
'$' || TO_CHAR(ROUND(AVG(p.amount)::numeric, 0), 'FM999,999') AS avg_payment
FROM expeditions e
INNER JOIN expedition_instances ei ON e.expedition_id = ei.expedition_id
INNER JOIN bookings b ON ei.instance_id = b.instance_id
INNER JOIN payments p ON b.booking_id = p.booking_id
WHERE p.payment_status = 'completed'
GROUP BY e.expedition_type
ORDER BY SUM(p.amount) DESC;
| Type | Bookings | Revenue | Avg Payment |
|——|———-|———|————-|
| Cultural | 288 | $516,346 | $1,793 |
| Photography | 404 | $494,942 | $1,225 |
| Safari | 369 | $454,140 | $1,231 |
| Hiking | 256 | $439,317 | $1,716 |
| Climbing | 283 | $395,880 | $1,399 |
Now you’ve gone from “I’ve never seen this database before” to “Cultural expeditions lead revenue with fewer bookings but higher average payments, while Photography has the most bookings but lower per-booking revenue.”
That took five queries and about 15 minutes.
Why This Process Works Everywhere
The Mister Rogers Blueprint isn’t a SQL technique. It’s a thinking framework:
1. Survey — What exists?
2. Sample — What does the data look like?
3. Connect — How do things relate?
4. Surprise — What’s unexpected?
5. Story — What business question can I answer?
This same process works whether you’re exploring a SQL database, a spreadsheet someone emailed you, an API response, or — eventually — a Python DataFrame. The tool changes. The approach doesn’t.
Over the past 29 weeks, we’ve covered a lot: eight different frameworks, advanced SQL techniques, career strategy, data quality, export formatting, window functions, and the analyst skill stack. Through all of it, this exploratory mindset is the through-line. Every framework we’ve discussed starts with curiosity and ends with insight.
Try This Today
Find a dataset you haven’t explored before. It could be:
A public dataset from Kaggle or data.gov
A different table in your company’s database you’ve never queried
An export a colleague sent you that’s been sitting in your downloads folder
Run the 5-step Mister Rogers process. See what story emerges. And if you find something interesting, reply to this email and tell me about it.
Until next time,
Brian ([say hi on twitter!](https://twitter.com/briangraves))
—
P.S. The Mister Rogers Blueprint is the very first framework in SQL for Business Impact, and everything else in the course builds on it. If you want the structured path from exploration to executive-level analysis, check it out at [sqlforbusinessimpact.com](https://sqlforbusinessimpact.com).
P.P.S. This wraps up our current newsletter season. Big things are coming — stay tuned for what’s next from BAA as we expand beyond SQL. More details landing in your inbox soon.
Want More SQL Insights Like This?
Join thousands of analysts getting weekly tips on turning data into business impact.
