SQL Tables

Course Tables β€” SQL for Product Growth | DataSosi
SQL for Product Growth · Course Tables · Reference Guide

Your Course Tables

The nine tables you will use throughout this SQL for Product Growth course β€” a complete SaaS product database covering user acquisition, session behaviour, in-app events, orders, payments, and A/B experiment results.

These are the tables you will use for this SQL for Product Growth course. Together they form a complete SaaS product analytics database called product_growth_sql_course, built from nine connected tables. The database mirrors the operational data stack of a real software product team β€” spanning user acquisition and lifecycle status (Free, Premium, Churned, Inactive), product catalogue with subscription plans and add-ons, session-level engagement data, granular in-app event tracking, a full order-to-payment pipeline, and a two-experiment A/B testing framework measuring conversion rate and retention. Every table in this database connects back to users β€” making user_id the central key for growth analysis.
9 Tables
User Lifecycle & Churn
Event-Level Analytics
A/B Experiment Framework

What These Tables Are For

  • Query a realistic SaaS product database to answer the core questions a product growth analyst faces daily: Who signed up, from which channel, on which device β€” and are they still active?
  • Track user behaviour at three levels of granularity β€” session (when and how long), event (what they did within a session), and order (what they purchased) β€” and join these layers to build complete user journeys
  • Analyse the subscription revenue model: which plan drives the most upgrades, which users hold add-ons, and how does paid conversion differ by acquisition channel and country
  • Evaluate A/B experiments using SQL: compare conversion_flag rates and revenue_generated between variant A and variant B β€” the fundamental growth experiment query used in product analytics teams
Click any section header to open or close it

The users table is the master record for every person who has signed up for the product. Eight users span four countries (Canada, USA, UK, Australia), three device types, four acquisition channels, two plan types, and four lifecycle statuses. User 3 (Noah Patel, USA) is the only Churned user. User 7 (Sophia Brown, Australia) is Inactive. The remaining six are Active β€” four on Free plans and four on Premium.

Churn and Inactivity β€” Users 3 and 7

User 3 (Noah Patel) has user_status = Churned β€” they signed up on a Free plan via Referral and left. Their session (1003) lasted only 12 minutes; their events show only a login and a pricing page view with no upgrade action. User 7 (Sophia Brown) is Inactive β€” also on a Free Referral plan, with the shortest session in the dataset (10 minutes, 7 pages). Filtering WHERE user_status IN (‘Churned’,’Inactive’) and joining to sessions and events reveals the behavioural patterns that precede disengagement β€” a core retention analysis in the course.

The Data
user_idfull_namesignup_datecountrydevice_typeacquisition_channelplan_typeuser_status
1Ava Thompson2024-01-05CanadaMobileOrganic SearchFreeActive
2Liam Chen2024-01-08CanadaDesktopPaid AdsPremiumActive
3Noah Patel2024-01-15USAMobileReferralFreeChurned
4Emma Rodriguez2024-02-01UKTabletOrganic SearchPremiumActive
5Olivia Martin2024-02-10CanadaDesktopEmail CampaignFreeActive
6Ethan Wilson2024-02-15USAMobilePaid AdsPremiumActive
7Sophia Brown2024-03-02AustraliaDesktopReferralFreeInactive
8Mason Lee2024-03-10CanadaMobileOrganic SearchPremiumActive
Column Breakdown
Column NameData TypeConstraintsExplanation
user_idINTPRIMARY KEYUnique identifier (1–8). The central key for the entire database β€” every other table links back to users via user_id.
full_nameVARCHAR(100)NoneUser’s full name. Used in report output and user-level queries.
signup_dateDATENoneDate of account creation. Ranges from 2024-01-05 to 2024-03-10. Used to calculate days since signup and cohort groupings.
countryVARCHAR(50)NoneCanada (4), USA (2), UK (1), Australia (1). Used to segment conversion and churn rates by geography.
device_typeVARCHAR(30)NoneMobile (4), Desktop (3), Tablet (1). The device used at signup β€” compare to session device_type for consistency checks.
acquisition_channelVARCHAR(50)NoneOrganic Search (3), Paid Ads (2), Referral (2), Email Campaign (1). The channel that drove the user to sign up.
plan_typeVARCHAR(20)NoneFree (4 β€” users 1, 3, 5, 7) or Premium (4 β€” users 2, 4, 6, 8). Used to calculate free-to-paid conversion rate.
user_statusVARCHAR(20)NoneActive (6), Churned (1 β€” user 3), Inactive (1 β€” user 7). The current lifecycle state of the user.

The products table defines the five purchasable items in the product catalogue. Three are subscription plans: Starter Plan (free, $0.00), Pro Plan ($29.99/month), and Team Plan ($79.99/month). Two are add-ons: Analytics Add-On ($14.99) and Growth Toolkit ($19.99). All five products are currently active (is_active = TRUE). Product IDs link to order_items, tying purchases to specific plan or add-on choices.

Subscription Plans vs Add-Ons

The Subscription category covers the core plan tier a user is on. The Add-On category covers optional extras purchased on top of a plan. In the order_items data, user 8 (Mason Lee) purchased both a Pro Plan (product 102) and the Analytics Add-On (product 104) in the same order β€” a bundle pattern common in SaaS upsell analysis. Grouping order_items by category and summing line_total breaks revenue into plan revenue vs add-on revenue.

The Data
product_idproduct_namecategorymonthly_priceis_active
101Starter PlanSubscription$0.00TRUE
102Pro PlanSubscription$29.99TRUE
103Team PlanSubscription$79.99TRUE
104Analytics Add-OnAdd-On$14.99TRUE
105Growth ToolkitAdd-On$19.99TRUE
Column Breakdown
Column NameData TypeConstraintsExplanation
product_idINTPRIMARY KEYUnique identifier (101–105). Referenced by order_items as a foreign key.
product_nameVARCHAR(100)NoneStarter Plan, Pro Plan, Team Plan, Analytics Add-On, Growth Toolkit.
categoryVARCHAR(50)NoneSubscription (3 β€” products 101–103) or Add-On (2 β€” products 104–105).
monthly_priceDECIMAL(10,2)NoneMonthly recurring price. $0.00 (Starter), $14.99 (Analytics Add-On), $19.99 (Growth Toolkit), $29.99 (Pro), $79.99 (Team).
is_activeBOOLEANNoneTRUE for all 5 products β€” no deprecated plans in the dataset. Filter WHERE is_active = TRUE in queries to exclude retired products in future analyses.

The sessions table records each user’s product session during the April 2024 observation window. One session per user in this dataset. Session IDs (1001–1008) link directly to events β€” every in-app event is tagged with the session_id in which it occurred. Session duration ranges from 10 minutes (user 7, Sophia Brown) to 40 minutes (user 6, Ethan Wilson). Longer sessions tend to contain more diverse event types and conversion actions.

Session Duration and Engagement

Session duration is a leading indicator of engagement quality. User 2 (Liam Chen, 35 minutes) and user 4 (Emma Rodriguez, 35 minutes) both have longer sessions and both converted β€” user 2 triggering an upgrade_plan event, user 4 using the Cohort Analysis feature. Users 3 and 7 (12 and 10 minutes respectively) are the two disengaged users β€” short sessions with low event counts. Joining sessions to events and grouping by session_duration_minutes shows the relationship between time-on-product and conversion likelihood.

The Data
session_iduser_idsession_startsession_endduration (min)traffic_sourcedevice_type
10011 β€” Ava Thompson2024-04-01 09:002024-04-01 09:1818Organic SearchMobile
10022 β€” Liam Chen2024-04-01 10:152024-04-01 10:5035Paid AdsDesktop
10033 β€” Noah Patel2024-04-02 11:002024-04-02 11:1212ReferralMobile
10044 β€” Emma Rodriguez2024-04-02 13:302024-04-02 14:0535Organic SearchTablet
10055 β€” Olivia Martin2024-04-03 08:452024-04-03 09:0015Email CampaignDesktop
10066 β€” Ethan Wilson2024-04-03 16:002024-04-03 16:4040Paid AdsMobile
10077 β€” Sophia Brown2024-04-04 12:102024-04-04 12:2010ReferralDesktop
10088 β€” Mason Lee2024-04-04 17:002024-04-04 17:2828Organic SearchMobile
Column Breakdown
Column NameData TypeConstraintsExplanation
session_idINTPRIMARY KEYUnique identifier (1001–1008). Referenced by events as a foreign key.
user_idINTFOREIGN KEY β†’ usersThe user this session belongs to. One session per user in this dataset.
session_start / session_endDATETIMENoneExact timestamps of the session. Use TIMEDIFF or TIMESTAMPDIFF to compute duration from these columns and verify against session_duration_minutes.
session_duration_minutesINTNonePre-calculated session length. Ranges from 10 (user 7) to 40 (user 6). Used for engagement benchmarking.
traffic_sourceVARCHAR(50)NoneOrganic Search (3), Paid Ads (2), Referral (2), Email Campaign (1). The channel that drove this session β€” matches acquisition_channel in users for returning users.
device_typeVARCHAR(30)NoneMobile (4), Desktop (3), Tablet (1). The device used during the session.

The events table is the most granular table in the database β€” it records every individual user action within a session. Fifteen events span 7 of the 8 users (user 7, Sophia Brown, has no events in the dataset β€” session 1007 produced no event records). Event types include: login (5), view_dashboard (2), start_trial (1), use_feature (3), upgrade_plan (1), view_pricing (1), complete_checkout (1), and use_feature (1 β€” Funnel Explorer). Events with NULL feature_name are page-level events with no specific feature interaction.

The Conversion Funnel in Events

The events table contains the full conversion funnel sequence: login β†’ view_dashboard β†’ start_trial (user 1, session 1001) and login β†’ use_feature β†’ upgrade_plan (user 2, session 1002) and login β†’ complete_checkout (user 6, session 1006). User 3 (Churned) goes login β†’ view_pricing but never proceeds β€” a classic drop-off pattern. Querying event sequences with ORDER BY event_timestamp within a session_id reveals exactly where users abandon the funnel.

The Data
event_iduser_idsession_idevent_nameevent_timestamppage_namefeature_name
200111001login2024-04-01 09:01Login PageNULL
200211001view_dashboard2024-04-01 09:03DashboardDashboard
200311001start_trial2024-04-01 09:10PricingTrial
200421002login2024-04-01 10:16Login PageNULL
200521002use_feature2024-04-01 10:25AnalyticsReport Builder
200621002upgrade_plan2024-04-01 10:40BillingPro Upgrade
200731003login2024-04-02 11:01Login PageNULL
200831003view_pricing2024-04-02 11:08PricingNULL
200941004login2024-04-02 13:32Login PageNULL
201041004use_feature2024-04-02 13:45AnalyticsCohort Analysis
201151005login2024-04-03 08:46Login PageNULL
201251005view_dashboard2024-04-03 08:50DashboardDashboard
201361006login2024-04-03 16:01Login PageNULL
201461006complete_checkout2024-04-03 16:30CheckoutSubscription Purchase
201581008use_feature2024-04-04 17:10Growth ToolsFunnel Explorer
Column Breakdown
Column NameData TypeConstraintsExplanation
event_idINTPRIMARY KEYUnique identifier (2001–2015). The 2000-series prefix distinguishes events from sessions (1000s).
user_idINTFOREIGN KEY β†’ usersThe user who triggered the event.
session_idINTFOREIGN KEY β†’ sessionsThe session during which this event occurred. Use to group events by session and reconstruct user journeys.
event_nameVARCHAR(50)Nonelogin (5), use_feature (3), view_dashboard (2), start_trial/upgrade_plan/view_pricing/complete_checkout/use_feature (1 each). The action taken.
event_timestampDATETIMENoneExact time the event fired. Order by event_timestamp within a session to reconstruct click sequences.
page_nameVARCHAR(50)NoneThe page the user was on when the event fired. Login Page, Dashboard, Pricing, Analytics, Billing, Checkout, Growth Tools.
feature_nameVARCHAR(50)NoneThe specific feature engaged with. NULL for page-level events (login, view_pricing). Non-NULL for feature interactions: Report Builder, Cohort Analysis, Funnel Explorer, Dashboard, Trial, Pro Upgrade, Subscription Purchase.

The orders table records the five subscription purchases made during the observation window. Orders link to users via user_id β€” notably, all five orders are placed by users who are either already Premium or converting to Premium during this period. Order 3005 (user 5, Olivia Martin) is Pending β€” a Free user whose Growth Toolkit add-on purchase has not yet been completed. Order 3004 (user 8, Mason Lee) is the highest-value at $49.98 β€” a two-item bundle.

Pending Order β€” User 5

Order 3005 (Olivia Martin, $19.99, Pending) is the only incomplete transaction in the dataset. Her corresponding payment (5005) is also Pending via Bank Transfer. Joining orders to users WHERE plan_type = ‘Free’ and order_status = ‘Pending’ identifies Free users who have initiated a purchase but not completed it β€” a high-priority segment for intervention in a product growth context, since they are in the conversion funnel but have not yet crossed it.

The Data
order_iduser_idorder_dateorder_statustotal_amount
30012 β€” Liam Chen2024-04-01Completed$29.99
30024 β€” Emma Rodriguez2024-04-02Completed$79.99
30036 β€” Ethan Wilson2024-04-03Completed$29.99
30048 β€” Mason Lee2024-04-04Completed$49.98
30055 β€” Olivia Martin2024-04-05Pending$19.99
Column Breakdown
Column NameData TypeConstraintsExplanation
order_idINTPRIMARY KEYUnique identifier (3001–3005). The 3000-series prefix distinguishes orders from sessions (1000s) and events (2000s). Referenced by order_items and payments.
user_idINTFOREIGN KEY β†’ usersThe user who placed the order. Users 3 and 7 (Churned/Inactive) have no orders β€” only Active/converting users appear here.
order_dateDATENoneDate the order was placed. All five orders fall within April 1–5, 2024 β€” the core observation window.
order_statusVARCHAR(30)NoneCompleted (4 β€” orders 3001–3004) or Pending (1 β€” order 3005).
total_amountDECIMAL(10,2)NoneOrder total. Ranges from $19.99 (Growth Toolkit only) to $79.99 (Team Plan). Order 3004 = $49.98 β€” a two-product bundle.

The order_items table records each product line within an order. Six items span five orders. Orders 3001, 3002, 3003, and 3005 each contain a single line item. Order 3004 (Mason Lee) contains two line items β€” a Pro Plan ($29.99) plus an Analytics Add-On ($19.99) β€” totalling $49.98. Joining order_items to products on product_id reveals which plans and add-ons are being purchased and at what volume.

Plan and Add-On Revenue Split

Of the six order line items, four are subscription plans (products 102 and 103) and two are add-ons (products 104 and 105). Subscription revenue: $29.99 + $79.99 + $29.99 + $29.99 = $169.96. Add-on revenue: $19.99 + $19.99 = $39.98. Grouping order_items by products.category and summing line_total gives the plan-vs-add-on revenue breakdown β€” a fundamental SaaS monetisation query.

The Data
order_item_idorder_idproduct_idquantityunit_priceline_total
40013001102 β€” Pro Plan1$29.99$29.99
40023002103 β€” Team Plan1$79.99$79.99
40033003102 β€” Pro Plan1$29.99$29.99
40043004102 β€” Pro Plan1$29.99$29.99
40053004104 β€” Analytics Add-On1$19.99$19.99
40063005105 β€” Growth Toolkit1$19.99$19.99
Column Breakdown
Column NameData TypeConstraintsExplanation
order_item_idINTPRIMARY KEYUnique identifier (4001–4006). The 4000-series distinguishes line items from orders (3000s).
order_idINTFOREIGN KEY β†’ ordersThe parent order. Order 3004 has two items (4004 and 4005); all others have one.
product_idINTFOREIGN KEY β†’ productsThe product purchased. Pro Plan (102) appears 3 times β€” the most popular paid plan.
quantityINTNoneAll quantities are 1 β€” subscription products are per-seat, not multi-unit in this dataset.
unit_priceDECIMAL(10,2)NonePrice charged at time of purchase β€” matches products.monthly_price for all items.
line_totalDECIMAL(10,2)Noneunit_price Γ— quantity. Since all quantities are 1, line_total equals unit_price throughout.

The payments table records the payment made against each order β€” one payment per order. Four payments are Paid (credit card and PayPal). Payment 5005 (Bank Transfer, order 3005, user 5 Olivia Martin) is Pending β€” matching the Pending order status. Total confirmed revenue from Paid payments: $29.99 + $79.99 + $29.99 + $49.98 = $189.95.

Revenue by Payment Method

Credit Card (payments 5001, 5003, 5004) accounts for $109.97 in confirmed revenue β€” the dominant payment method. PayPal (payment 5002) covers the highest single transaction at $79.99 (the Team Plan). Bank Transfer (payment 5005) is Pending β€” it has not yet cleared. Grouping payments by payment_method and summing amount_paid WHERE payment_status = ‘Paid’ gives total collected revenue by channel β€” a standard finance and growth reporting query.

The Data
payment_idorder_idpayment_datepayment_methodpayment_statusamount_paid
500130012024-04-01Credit CardPaid$29.99
500230022024-04-02PayPalPaid$79.99
500330032024-04-03Credit CardPaid$29.99
500430042024-04-04Credit CardPaid$49.98
500530052024-04-05Bank TransferPending$19.99
Column Breakdown
Column NameData TypeConstraintsExplanation
payment_idINTPRIMARY KEYUnique identifier (5001–5005). The 5000-series distinguishes payments from order_items (4000s).
order_idINTFOREIGN KEY β†’ ordersThe order this payment settles. One-to-one with orders in this dataset.
payment_dateDATENoneAll payments dated the same as their order β€” same-day processing for completed payments.
payment_methodVARCHAR(30)NoneCredit Card (3), PayPal (1), Bank Transfer (1 β€” Pending).
payment_statusVARCHAR(30)NonePaid (4) or Pending (1 β€” payment 5005). Filter WHERE payment_status = ‘Paid’ for confirmed revenue calculations.
amount_paidDECIMAL(10,2)NonePayment value β€” matches orders.total_amount for each order.

The experiments table defines the two A/B tests running during the observation period. Experiment 6001 (New Pricing Page Test) ran April 1–15 and is Completed β€” it measured Conversion Rate. Experiment 6002 (Onboarding Email Test) started April 5 and is still Running β€” it measures Retention Rate. Each experiment links to multiple user-level results in experiment_results via experiment_id.

Two Experiments β€” Two Growth Levers

Experiment 6001 targets the top of the conversion funnel β€” does a new pricing page design drive more users to purchase? Experiment 6002 targets post-signup retention β€” does a different onboarding email sequence keep users active longer? Together they represent the two most common growth experiment types: acquisition-side optimisation and retention-side optimisation. Joining experiments to experiment_results lets you compare variant A vs variant B conversion rates for each.

The Data
experiment_idexperiment_namestart_dateend_datetarget_metricexperiment_status
6001New Pricing Page Test2024-04-012024-04-15Conversion RateCompleted
6002Onboarding Email Test2024-04-052024-04-20Retention RateRunning
Column Breakdown
Column NameData TypeConstraintsExplanation
experiment_idINTPRIMARY KEYUnique identifier (6001–6002). Referenced by experiment_results as a foreign key.
experiment_nameVARCHAR(100)NoneDescriptive name. New Pricing Page Test and Onboarding Email Test.
start_date / end_dateDATENoneExperiment duration. Experiment 6001 ran 14 days; experiment 6002 runs 15 days. Use DATEDIFF to calculate duration.
target_metricVARCHAR(50)NoneConversion Rate (experiment 6001) or Retention Rate (experiment 6002). Defines what success looks like for each test.
experiment_statusVARCHAR(30)NoneCompleted (1 β€” experiment 6001) or Running (1 β€” experiment 6002). Filter WHERE experiment_status = ‘Completed’ before drawing conclusions.

The experiment_results table records one row per user per experiment β€” the variant they were assigned (A or B), whether they converted (conversion_flag = TRUE/FALSE), and the revenue they generated. For experiment 6001 (Pricing Page Test): users 2, 4, and 6 were assigned Variant B and all converted; users 1 and 5 were assigned Variant A and did not convert. For experiment 6002 (Onboarding Email): user 7 (A, no conversion) vs user 8 (B, converted, $49.98).

Variant A vs Variant B β€” Experiment 6001

In experiment 6001, Variant B (the new pricing page) achieved a 3/3 (100%) conversion rate with $139.97 in revenue generated. Variant A achieved 0/2 (0%) conversion and $0 revenue. While the sample size is small (5 users), the directional signal is clear: the new pricing page drove all conversions. The core query β€” SELECT variant, COUNT(*) as users, SUM(conversion_flag) as conversions, SUM(revenue_generated) as revenue FROM experiment_results WHERE experiment_id = 6001 GROUP BY variant β€” produces the A/B summary table used in product growth reporting.

The Data
result_idexperiment_iduser_idvariantconversion_flagrevenue_generated
700160011 β€” Ava ThompsonAFALSE$0.00
700260012 β€” Liam ChenBTRUE$29.99
700360014 β€” Emma RodriguezBTRUE$79.99
700460015 β€” Olivia MartinAFALSE$0.00
700560016 β€” Ethan WilsonBTRUE$29.99
700660027 β€” Sophia BrownAFALSE$0.00
700760028 β€” Mason LeeBTRUE$49.98
Column Breakdown
Column NameData TypeConstraintsExplanation
result_idINTPRIMARY KEYUnique identifier (7001–7007). The 7000-series distinguishes results from experiments (6000s).
experiment_idINTFOREIGN KEY β†’ experimentsWhich experiment this result belongs to. 5 results for experiment 6001; 2 for experiment 6002.
user_idINTFOREIGN KEY β†’ usersThe user who participated. Joining to users adds country, device, acquisition_channel for subgroup analysis.
variantVARCHAR(10)NoneA (control β€” 3 users) or B (treatment β€” 4 users). Variant B is the new experience being tested.
conversion_flagBOOLEANNoneTRUE (4 β€” all Variant B users) or FALSE (3 β€” all Variant A users). In experiment 6001, Variant B = 100% conversion; Variant A = 0%.
revenue_generatedDECIMAL(10,2)NoneRevenue attributed to the user during the experiment window. $0.00 for non-converters; $29.99–$79.99 for converters. SUM by variant gives total revenue impact of each version.

Quick Reference β€” All 9 Tables

The complete product_growth_sql_course database at a glance.

Users

8 rows β€” Free/Premium, 4 countries, 4 channels. PK: user_id (1–8). Users 3 (Churned) and 7 (Inactive) flagged.

Products

5 rows β€” 3 plans, 2 add-ons, all active. PK: product_id (101–105). Pro Plan = most purchased.

Sessions

8 rows β€” 1 per user, 10–40 min duration. PK: session_id (1001–1008). Sessions 1003 and 1007 = shortest (disengaged users).

Events

15 rows β€” 7 event types, NULL feature_name for page events. PK: event_id (2001–2015). User 7 has no events.

Orders

5 rows β€” 4 Completed, 1 Pending. PK: order_id (3001–3005). Order 3004 = highest value ($49.98 bundle).

Order Items

6 rows β€” 4 plan lines, 2 add-on lines. PK: order_item_id (4001–4006). Order 3004 = only multi-line order.

Payments

5 rows β€” 4 Paid, 1 Pending. PK: payment_id (5001–5005). Confirmed revenue = $189.95.

Experiments

2 rows β€” 1 Completed, 1 Running. PK: experiment_id (6001–6002). Metrics: Conversion Rate and Retention Rate.

Experiment Results

7 rows β€” Variant A (3 users, 0 conversions) vs Variant B (4 users, 4 conversions). PK: result_id (7001–7007).

User Lifecycle Churn Free-to-Paid Conversion Session Duration Event Funnel A/B Testing Variant Conversion Flag BOOLEAN DATETIME IS NULL GROUP BY SUM / COUNT ROAS MRR