1. Lighthouse

Level 2 · The cohort retention table

The request

From Catherine Hale, Chief Executive Officer

“Jordan says we keep our customers better than we used to. I'd like to see it. For each group of new customers, how many came back for a second order within three months, and within a year?”

Your goal

Using booked orders (status IN ('completed', 'refunded')) and the firsts CTE in the starter, return one row per cohort for first orders before 2025-01-01 with columns cohort (DATE, the quarter start from date_trunc('quarter', first_at)), customers, repeat_90_pct and repeat_365_pct: the share of the cohort with another booked order after the first one and no more than 90 (or 365) days after it (order_date <= first_at + INTERVAL 90 DAY), times 100 and rounded to 1. Sort by cohort.

  • Read from the customers tablenot done yet
  • Read from the orders tablenot done yet
  • Show exactly cohort customers repeat_90_pct repeat_365_pctnot done yet

Your query

SQL

Loading the editor…

    ResultPreview of customers · press Run to see yours
    Preview of customers
    customer_idfirst_namelast_nameemailcity
    1OwenHudsonowen.hudson@icloud.comSan Francisco
    2DouglasMendozadmendoza69@gmail.comAtlanta
    3HenryBrookshbrooks@lakesidecafe.comLos Angeles
    4BrianGrahambgraham@bluecedarhomes.comSeattle

    Mote checks your result

    Press Run. Each row that matches the goal becomes a firefly in your lantern.

    Tables

    Harbor & Pine store data, ready to query.

    customers2,018 rows · 9 columns
    • customer_idinteger
    • first_namevarchar
    • last_namevarchar
    • emailvarchar
    • cityvarchar
    • statevarchar
    • signup_datedate
    • segmentvarchar
    • referral_sourcevarchar
    First 5 rows of customers
    customer_idfirst_namelast_nameemailcitystatesignup_datesegmentreferral_source
    1OwenHudsonowen.hudson@icloud.comSan FranciscoCA2022-06-02consumersearch
    2DouglasMendozadmendoza69@gmail.comAtlantaGA2022-06-02consumerNULL
    3HenryBrookshbrooks@lakesidecafe.comLos AngelesCA2022-06-04businessNULL
    4BrianGrahambgraham@bluecedarhomes.comSeattleWA2022-06-06businesspinterest
    5KyleJimenezkjimenez27@yahoo.comIndianapolisIN2022-06-07consumerNULL
    orders12,000 rows · 7 columns
    • order_idinteger
    • customer_idinteger
    • order_datetimestamp
    • statusvarchar
    • channelvarchar
    • shipping_feedecimal
    • coupon_codevarchar
    First 5 rows of orders
    order_idcustomer_idorder_datestatuschannelshipping_feecoupon_code
    10011252023-01-01 20:51:19completedweb0.00NULL
    10021562023-01-02 07:58:46completedweb0.00NULL
    1003222023-01-02 10:25:27completedmarketplace4.99WELCOME10
    1004482023-01-02 11:21:51completedmarketplace4.99WELCOME10
    1005822023-01-02 11:43:36completedweb0.00WELCOME10
    products120 rows · 8 columns
    • product_idinteger
    • namevarchar
    • categoryvarchar
    • subcategoryvarchar
    • unit_pricedecimal
    • unit_costdecimal
    • launched_ondate
    • is_activeboolean
    First 5 rows of products
    product_idnamecategorysubcategoryunit_priceunit_costlaunched_onis_active
    101Vale Velvet LoveseatFurnitureSofas1659.00NULL2023-09-11true
    102Alder Oak Coffee TableFurnitureTables919.00503.502024-05-16true
    103Orchard Rattan Dining ChairFurnitureChairs789.00429.872023-05-27true
    104Upland Oak BookcaseFurnitureStorage429.00214.702022-12-20true
    105Avery Leather Bed FrameFurnitureBeds449.00232.702021-08-31true
    order_items30,338 rows · 6 columns
    • order_item_idinteger
    • order_idinteger
    • product_idinteger
    • quantityinteger
    • unit_pricedecimal
    • discount_pctdecimal
    First 5 rows of order_items
    order_item_idorder_idproduct_idquantityunit_pricediscount_pct
    11001121931.990.00
    21001154311.990.00
    31002154411.990.00
    410021941149.000.00
    51002193219.990.00
    returns1,673 rows · 5 columns
    • return_idinteger
    • order_item_idinteger
    • returned_ondate
    • reasonvarchar
    • refund_amountdecimal
    First 5 rows of returns
    return_idorder_item_idreturned_onreasonrefund_amount
    1142023-01-10damaged83.69
    2422023-01-10wrong_item19.99
    31052023-01-14wrong_item10.99
    4242023-01-16changed_mind26.99
    51262023-01-16late20.99
    employees60 rows · 8 columns
    • employee_idinteger
    • first_namevarchar
    • last_namevarchar
    • departmentvarchar
    • titlevarchar
    • manager_idinteger
    • hire_datedate
    • salaryinteger
    First 5 rows of employees
    employee_idfirst_namelast_namedepartmenttitlemanager_idhire_datesalary
    1CatherineHaleExecutiveChief Executive OfficerNULL2016-03-01285000
    2RobertKimExecutiveChief Operating Officer12017-01-09235000
    3MeganCollinsSalesHead of Sales12018-04-16172000
    4ChloeGutierrezSalesAccount Executive32020-01-2172000
    5FrankBellSalesAccount Executive32023-05-2173000
    web_sessions40,000 rows · 7 columns
    • session_idinteger
    • customer_idinteger
    • started_attimestamp
    • devicevarchar
    • sourcevarchar
    • pages_viewedinteger
    • convertedboolean
    First 5 rows of web_sessions
    session_idcustomer_idstarted_atdevicesourcepages_viewedconverted
    1NULL2023-01-01 23:02:24mobilepaid1false
    2182023-01-01 15:07:49desktoppaid1false
    3NULL2023-01-01 16:55:46desktopdirect7false
    4NULL2023-01-01 12:43:28mobileorganic3false
    5NULL2023-01-01 13:06:21mobilesocial2false
    marketing_spend3,276 rows · 3 columns
    • spend_datedate
    • channelvarchar
    • amountdecimal
    First 5 rows of marketing_spend
    spend_datechannelamount
    2023-01-01paid492.99
    2023-01-01email37.38
    2023-01-01social200.53
    2023-01-02paid709.13
    2023-01-02email64.13

    The lesson

    Retention needs a window

    “What share of customers came back?” has no answer until you say within how long. Give a customer three years and nearly everyone at Harbor & Pine orders again; give them a week and almost nobody does. A cohort retention table fixes the window and measures every cohort against it: “repeat within 90 days of the first order”, “repeat within 365 days”.

    The window is counted from each customer’s own first order, not from the start of the quarter. A customer who first bought on March 30 and one who first bought on January 2 both get exactly 90 days.

    One flag per customer

    Join each customer’s later booked orders onto their first order, and turn “is there one inside the window?” into a 0/1 flag:

    MAX(CASE WHEN b.order_date <= f.first_at + INTERVAL 90 DAY THEN 1 ELSE 0 END) AS r90

    MAX collapses many later orders into one flag per customer: a customer with five repeat orders still counts once. The join must be a LEFT JOIN with b.order_date > f.first_at in the ON clause, so one-time buyers stay in the table with a flag of 0. Put that condition in WHERE and they vanish from the denominator, and retention jumps.

    Then the cohort’s rate is the average of the flags: SUM(r90) * 100.0 / COUNT(*).

    Fair windows only

    A 365-day window only makes sense for customers who have had 365 days. Anyone whose first order was in 2025 has not, so their missing repeats are not a verdict, just a lack of time. That is why this table stops at first orders before 2025-01-01. This is called right-censoring: the outcome is cut off by the end of the data, not by the customer.

    Reading the table

    Read down a column to see whether newer cohorts behave like older ones. Read across a row to see how retention builds with a longer window. Compare holiday cohorts with holiday cohorts: gift buyers from November behave differently from customers who found the store in spring.

    Watch the first cohort of any dataset. If the data begins in January 2023, the “2023Q1 cohort” is partly customers who were already loyal before the data starts. Here that is 116 of 177 people, which is why that row looks so good.

    Common mistakes

    • No window. “Ever came back” rewards old cohorts for being old.
    • WHERE instead of ON. Filtering the later orders in WHERE drops one-time buyers.
    • Counting orders instead of customers. COUNT(b.order_id) measures how much repeaters buy, not how many came back.

    Pick what may run on this site. You can change this any time from "Cookie settings" at the bottom of every page.