The request

From Jordan Reyes, Head of Marketing
Your goal
For customers with signup_date from 2024-01-01 up to (not including) 2025-10-01, find each customer's first completed order date (the date part of their earliest completed order; customers without one count as not activated). Return one row per signup quarter with: signup_quarter (first day of the quarter, as a DATE), signups (customers who signed up in the quarter), activated_30d (those whose first completed order date is at most 30 days after signup_date) and activation_pct (activated_30d / signups * 100, rounded to 1). Sort by signup_quarter ascending.
- Read from the
customerstablenot done yet - Read from the
orderstablenot done yet - Show exactly
signup_quartersignupsactivated_30dactivation_pctnot done yet
Your query
Loading the editor…
Reference solution
| customer_id | first_name | last_name | city | |
|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle |
Mote checks your result
Press Run. Each row that matches the goal becomes a firefly in your lantern.
What Jordan gets, and why
Tables
Harbor & Pine store data, ready to query.
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 |
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 |
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 |
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 |
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 |
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 |
The lesson
Activation asks: of the people who signed up, how many did the thing that makes them a real customer, within a fixed time? At Harbor & Pine that thing is a first completed order within 30 days of signup. It is a cohort metric: you group people by when they joined, not by when they bought.
Start from the people, not the events
The denominator is signups, so the query starts from customers and attaches each person’s first
completed order with a LEFT JOIN:
WITH first_orders AS (
SELECT customer_id, MIN(CAST(order_date AS DATE)) AS first_order_day
FROM orders
WHERE status = 'completed'
GROUP BY customer_id
)
SELECT c.customer_id, c.signup_date,
f.first_order_day - c.signup_date AS days_to_first_order
FROM customers AS c
LEFT JOIN first_orders AS f ON f.customer_id = c.customer_id;
Subtracting two DATEs in DuckDB and Postgres gives a whole number of days. Customers who never
completed an order get NULL, and a NULL never passes <= 30, so they count as not activated, which
is exactly right.
Worked example: 2024 to Q3 2025
| signup_quarter | signups | activated_30d | activation_pct |
|---|---|---|---|
| 2024-01-01 | 105 | 72 | 68.6 |
| 2024-07-01 | 111 | 81 | 73.0 |
| 2025-04-01 | 171 | 104 | 60.8 |
| 2025-07-01 | 171 | 102 | 59.6 |
Activation has drifted from around 70% in 2024 to around 60% in mid-2025. That is a real signal worth raising, with one honest caveat: these cohorts are 105 to 235 people, so a few points of movement between neighboring quarters can be noise.
Censoring: why the task stops at Q3 2025
The data ends on 2025-12-31. Someone who signed up on December 20 has had 11 days, not 30, to place an order. Run the same query by month and December 2025 shows 45.2% activation against 58.2% in November. December customers are not worse; they have not had time yet. This is called right censoring, and the fix is to report only cohorts whose full window has passed.
Common mistakes
- Inner join to orders. Non-buyers disappear from the denominator.
- Using any order instead of the first. “Ordered within 30 days” means the first completed order, not any order whose date happens to be close to signup.
- Mixing signup cohorts with order dates. Group by signup quarter; the order date only decides whether someone activated.
In SQL Server
Use DATEDIFF(day, c.signup_date, f.first_order_day) <= 30, since subtracting dates is not
allowed. Quarter starts come from
DATEFROMPARTS(YEAR(signup_date), (DATEPART(quarter, signup_date) - 1) * 3 + 1, 1), or
DATETRUNC(quarter, signup_date) in SQL Server 2022 and later.
Lantern lit!
Practised: activationcohortleft joindate differencecensoring
- Solved
- No hints
- First run
