The request

From Laura Bennett, Head of Finance
Your goal
Return one row per acquisition year (first_year 2023 and 2024 only; 2025 has no full first year yet) with: first_year, new_customers, cac (that year's total marketing spend / new_customers, rounded to 2), first_year_margin (margin per customer from orders placed within 365 days of the customer's first order, i.e. order_date < first_at + INTERVAL 365 DAY, rounded to 2), margin_to_date (all margin per customer through 2025, rounded to 2), ltv_to_cac (margin_to_date / cac, rounded to 2) and payback_months (cac / (first_year_margin / 12), rounded to 1). Per-customer values divide by new_customers. Use unrounded values in every formula. Sort by first_year. The starter's CTEs give first orders, margin per kept line and spend per year.
- Read from the
productstablenot done yet - Read from the
orderstablenot done yet - Show exactly
first_yearnew_customerscacfirst_year_marginmargin_to_dateltv_to_cacpayback_monthsnot done yet
Your query
Loading the editor…
Reference solution
| product_id | name | category | subcategory | unit_price |
|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 |
Mote checks your result
Press Run. Each row that matches the goal becomes a firefly in your lantern.
What Laura gets, and why
Tables
Harbor & Pine store data, ready to query.
products120 rows · 8 columns
product_idintegernamevarcharcategoryvarcharsubcategoryvarcharunit_pricedecimalunit_costdecimallaunched_ondateis_activeboolean
| product_id | name | category | subcategory | unit_price | unit_cost | launched_on | is_active |
|---|---|---|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 | NULL | 2023-09-11 | true |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 | 503.50 | 2024-05-16 | true |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 | 429.87 | 2023-05-27 | true |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 | 214.70 | 2022-12-20 | true |
| 105 | Avery Leather Bed Frame | Furniture | Beds | 449.00 | 232.70 | 2021-08-31 | true |
orders12,000 rows · 7 columns
order_idintegercustomer_idintegerorder_datetimestampstatusvarcharchannelvarcharshipping_feedecimalcoupon_codevarchar
| order_id | customer_id | order_date | status | channel | shipping_fee | coupon_code |
|---|---|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web | 0.00 | NULL |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web | 0.00 | NULL |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace | 4.99 | WELCOME10 |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace | 4.99 | WELCOME10 |
| 1005 | 82 | 2023-01-02 11:43:36 | completed | web | 0.00 | WELCOME10 |
order_items30,338 rows · 6 columns
order_item_idintegerorder_idintegerproduct_idintegerquantityintegerunit_pricedecimaldiscount_pctdecimal
| order_item_id | order_id | product_id | quantity | unit_price | discount_pct |
|---|---|---|---|---|---|
| 1 | 1001 | 121 | 9 | 31.99 | 0.00 |
| 2 | 1001 | 154 | 3 | 11.99 | 0.00 |
| 3 | 1002 | 154 | 4 | 11.99 | 0.00 |
| 4 | 1002 | 194 | 1 | 149.00 | 0.00 |
| 5 | 1002 | 193 | 2 | 19.99 | 0.00 |
returns1,673 rows · 5 columns
return_idintegerorder_item_idintegerreturned_ondatereasonvarcharrefund_amountdecimal
| return_id | order_item_id | returned_on | reason | refund_amount |
|---|---|---|---|---|
| 1 | 14 | 2023-01-10 | damaged | 83.69 |
| 2 | 42 | 2023-01-10 | wrong_item | 19.99 |
| 3 | 105 | 2023-01-14 | wrong_item | 10.99 |
| 4 | 24 | 2023-01-16 | changed_mind | 26.99 |
| 5 | 126 | 2023-01-16 | late | 20.99 |
marketing_spend3,276 rows · 3 columns
spend_datedatechannelvarcharamountdecimal
| spend_date | channel | amount |
|---|---|---|
| 2023-01-01 | paid | 492.99 |
| 2023-01-01 | 37.38 | |
| 2023-01-01 | social | 200.53 |
| 2023-01-02 | paid | 709.13 |
| 2023-01-02 | 64.13 |
customers2,018 rows · 9 columns
customer_idintegerfirst_namevarcharlast_namevarcharemailvarcharcityvarcharstatevarcharsignup_datedatesegmentvarcharreferral_sourcevarchar
| customer_id | first_name | last_name | city | state | signup_date | segment | referral_source | |
|---|---|---|---|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco | CA | 2022-06-02 | consumer | search |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta | GA | 2022-06-02 | consumer | NULL |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles | CA | 2022-06-04 | business | NULL |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle | WA | 2022-06-06 | business | |
| 5 | Kyle | Jimenez | kjimenez27@yahoo.com | Indianapolis | IN | 2022-06-07 | consumer | NULL |
employees60 rows · 8 columns
employee_idintegerfirst_namevarcharlast_namevarchardepartmentvarchartitlevarcharmanager_idintegerhire_datedatesalaryinteger
| employee_id | first_name | last_name | department | title | manager_id | hire_date | salary |
|---|---|---|---|---|---|---|---|
| 1 | Catherine | Hale | Executive | Chief Executive Officer | NULL | 2016-03-01 | 285000 |
| 2 | Robert | Kim | Executive | Chief Operating Officer | 1 | 2017-01-09 | 235000 |
| 3 | Megan | Collins | Sales | Head of Sales | 1 | 2018-04-16 | 172000 |
| 4 | Chloe | Gutierrez | Sales | Account Executive | 3 | 2020-01-21 | 72000 |
| 5 | Frank | Bell | Sales | Account Executive | 3 | 2023-05-21 | 73000 |
web_sessions40,000 rows · 7 columns
session_idintegercustomer_idintegerstarted_attimestampdevicevarcharsourcevarcharpages_viewedintegerconvertedboolean
| session_id | customer_id | started_at | device | source | pages_viewed | converted |
|---|---|---|---|---|---|---|
| 1 | NULL | 2023-01-01 23:02:24 | mobile | paid | 1 | false |
| 2 | 18 | 2023-01-01 15:07:49 | desktop | paid | 1 | false |
| 3 | NULL | 2023-01-01 16:55:46 | desktop | direct | 7 | false |
| 4 | NULL | 2023-01-01 12:43:28 | mobile | organic | 3 | false |
| 5 | NULL | 2023-01-01 13:06:21 | mobile | social | 2 | false |
The lesson
Two questions about every customer you buy
LTV:CAC compares what a customer is worth with what it cost to acquire them. A ratio of 3 means every dollar spent on acquisition comes back three times as margin. CAC payback asks how long that takes: the number of months of margin needed to earn back the acquisition cost.
LTV:CAC = margin LTV / CAC
payback months = CAC / monthly margin per new customer
Both use margin, not revenue. At the 2025 margin rate of 53.84%, a customer who keeps $1,000 of purchases leaves the store about $538 to pay for the ad that found them.
Margin, by cohort
Margin here is the discounted line value minus quantity * unit_cost, on valid lines of booked
orders that were not returned. Nine products have no cost; their lines are left out. Per-customer
numbers divide by the cohort’s size (everyone acquired that year), not only by customers who have
margin lines.
Monthly margin for payback comes from each customer’s first 365 days, divided by 12. Why the first year? Payback is about the early months, and every cohort can be compared over the same age. That is why 2025 is excluded: its customers have not had a full year yet.
The result
first_year new_customers cac first_year_margin margin_to_date ltv_to_cac payback_months
2023 574 665.84 1727.67 2995.81 4.50 4.6
2024 525 841.70 1020.11 1276.82 1.52 9.9
Both cohorts pay back within a year. The 2023 cohort looks far stronger, for two reasons you have met before: it has had three years to buy instead of two, and it includes regulars who signed up before 2023 and only look new because the data starts then.
Reading the ratio honestly
The ratio uses margin to date, so it grows every month a cohort keeps buying. A young cohort with 1.52 is not a failure; compare cohorts at the same age, or use a predictive margin LTV (level 4) when you need a forward number. Also remember that blended CAC charges all spend, including email to existing customers, to new customers.
Common mistakes
- Revenue LTV over CAC. It overstates the ratio roughly twofold here, because about half of revenue pays for the products.
- Joining spend to lines. Joining
marketing_spendbefore aggregating repeats each spend row per match. Aggregate each input to one row per year first. - Dividing by customers with margin. A customer whose only order was returned still cost CAC.
Interview note
“What is a good LTV:CAC?” The textbook answer is about 3:1 with payback under 12 months. The better answer adds that it depends on the LTV definition and the age of the cohort.
Lantern lit!
Practised: ltv cacpayback periodcacmargincohortcte
- Solved
- No hints
- First run
