SaaSCloud
B2B SaaS / subscription analytics
SaaSCloud sells a per-seat B2B collaboration product to small businesses, mid-market companies and enterprises. Its data covers customer accounts, subscription periods (each upgrade, downgrade or seat change starts a new period), invoices and payment failures, churn reasons, daily product usage and support tickets. That is everything needed for MRR movements, net revenue retention, seat utilisation and churn-risk questions, which come up in almost every SaaS analytics interview.
See the SaaSCloud tables
SaaSCloud schema
All tables live in the saascloud schema, so write saascloud.customers in your queries.
saascloud.customers
Customer accounts (companies).
customer_id(INT) — PKcompany_name(VARCHAR(80))industry(VARCHAR(30))country(VARCHAR(40))segment(VARCHAR(12)) — 'SMB', 'Mid-Market', 'Enterprise'signup_date(DATE)
saascloud.plans
Plans and their list price per seat.
plan_id(INT) — PKplan_name(VARCHAR(20)) — 'Starter', 'Growth', 'Business', 'Enterprise'tier(INT) — 1 (lowest) to 4 (highest)price_per_seat(DECIMAL(8,2)) — USD per seat per month
saascloud.subscriptions
Subscription periods. A plan or seat change ends the current period and starts a new one the next day.
subscription_id(INT) — PKcustomer_id(INT) — FK → customers.customer_idplan_id(INT) — FK → plans.plan_idseats(INT)billing_period(VARCHAR(8)) — 'monthly' or 'yearly' (yearly gets 20% off)mrr(DECIMAL(12,2)) — monthly recurring revenue of this period, USDstart_date(DATE)end_date(DATE) — nullable; last day of the period; NULL while runningchange_type(VARCHAR(10)) — how the period began: 'new', 'upgrade', 'downgrade'
saascloud.invoices
Invoices and payment attempts (USD).
invoice_id(INT) — PKcustomer_id(INT) — FK → customers.customer_idsubscription_id(INT) — FK → subscriptions.subscription_idinvoice_date(DATE)due_date(DATE)amount(DECIMAL(12,2))status(VARCHAR(8)) — 'PAID', 'PENDING', 'FAILED'paid_at(DATE) — nullable
saascloud.churn_reports
One row per customer that cancelled.
churn_id(INT) — PKcustomer_id(INT) — FK → customers.customer_idchurn_date(DATE)churn_reason(VARCHAR(30)) — 'price', 'missing_features', 'switched_competitor', 'business_closed', 'low_usage'
saascloud.usage_metrics
Daily product usage per customer (last 120 days).
usage_id(INT) — PKcustomer_id(INT) — FK → customers.customer_idmetric_date(DATE)active_users(INT) — distinct users active that dayapi_calls(INT)storage_gb(DECIMAL(10,2))
saascloud.support_tickets
Support requests.
ticket_id(INT) — PKcustomer_id(INT) — FK → customers.customer_idcreated_at(TIMESTAMP)priority(VARCHAR(8)) — 'low', 'medium', 'high', 'urgent'resolved_at(TIMESTAMP) — nullable; NULL while open
Beginner (10)
- BeginnerCustomers by segmentOpen now
- BeginnerPlan price listOpen now
- BeginnerRunning subscriptions by plan
- BeginnerNew customers by country (last 90 days)
- BeginnerFailed invoices in the last 30 days
- BeginnerWhy customers leave
- BeginnerSeats under contract
- BeginnerEnterprise customers in India
- BeginnerOpen support tickets by priority
- BeginnerAverage daily API calls (last 7 days)
Intermediate (10)
- IntermediateCurrent MRR by plan
- IntermediateARPA by segment
- IntermediateOverdue invoices
- IntermediateSeat utilisation (last 28 days)
- IntermediatePaying customers with no recent usage
- IntermediateNew customers and new MRR per month
- IntermediateMonthly vs yearly billing mix
- IntermediateResolution time by priority
- IntermediateInvoice collection rate
- IntermediateHeaviest API users (last 30 days)
Advanced (24)
- AdvancedMonthly MRR movements
- AdvancedNet revenue retention (12 months)
- AdvancedMonthly logo churn rate
- AdvancedLogo retention by signup quarter
- AdvancedUsage drop alert
- AdvancedHow long until customers upgrade?
- AdvancedPayment recovery after failure
- AdvancedAccounts ready for more seats
- AdvancedDo churned customers raise more tickets first?
- AdvancedARR at each quarter end
- AdvancedGross revenue retention with expansion capped
- AdvancedOverlapping MRR history periods per customer
- AdvancedConsecutive observed high-usage days
- AdvancedUsage-active retention on a fixed opening cohort
- AdvancedAtomic invoice paid-state update
- AdvancedObserved versus still-open support resolution times
- AdvancedLock a bounded support-ticket work batch
- AdvancedJSON usage summary without nested-aggregate errors
- AdvancedInspect indexes supporting invoice lookups
- AdvancedSnapshot seat price versus current plan catalogue
- AdvancedCustomer invoice/ticket summary without multiplicative joins
- AdvancedReceivable aging with explicit as-of and open status
- AdvancedBuild a partial index for unpaid-invoice access
- AdvancedRange partitioning and pruning of an invoice stage
Mock interview round (5)
- AdvancedMock round 1: MRR today vs a year ago
- AdvancedMock round 2: At-risk accounts
- AdvancedMock round 3: Plan change paths
- AdvancedMock round 4: Lost MRR by churn reason
- AdvancedMock round 5: Segment scorecard