The request

From Priya Shah, Head of Data
Your goal
Step 1 of 3. For completed orders placed in 2025, return one row per month with: month (a DATE, first of the month), orders, net_revenue (rounded to 2) and shipping_revenue (each order's shipping_fee counted once, rounded to 2). Sort by month ascending.
- Read from the
orderstablenot done yet - Read from the
order_itemstablenot done yet - Show exactly
monthordersnet_revenueshipping_revenuenot done yet
Step 2 of 3. For orders of every status placed in 2025, return one row per channel with: channel, orders, cancelled_orders (orders with status 'cancelled') and cancel_rate_pct (cancelled_orders / orders * 100, rounded to 2).
- Read from the
orderstablenot done yet - Show exactly
channelorderscancelled_orderscancel_rate_pctnot done yet - 3 rowsnot done yet
Step 3 of 3. Among customers with at least one completed order in 2025, return one row per segment (from customers) with: segment, buyers (customers with at least one completed 2025 order), repeat_buyers (those with two or more) and repeat_rate_pct (repeat_buyers / buyers * 100, rounded to 1).
- Read from the
customerstablenot done yet - Read from the
orderstablenot done yet - Show exactly
segmentbuyersrepeat_buyersrepeat_rate_pctnot done yet
Step 1 · your query
Loading the editor…
Reference solution
| order_id | customer_id | order_date | status | channel |
|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace |
Mote checks your result
Press Run. Each row that matches the goal becomes a firefly in your lantern.
Step 2 · your query
Loading the editor…
Reference solution
| order_id | customer_id | order_date | status | channel |
|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace |
Mote checks your result
Press Run. Each row that matches the goal becomes a firefly in your lantern.
Step 3 · 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 Priya gets, and why
Tables
Harbor & Pine store data, ready to query.
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 |
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 |
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 |
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
Inherited reports rarely have just one bug. This boss gives you three queries from the same pack. Each runs, each returns a tidy table, and each tells the board something false.
Step 1: monthly revenue and shipping
Two bugs from this chapter. The join to order_items repeats every order’s shipping_fee once per
line, so shipping is inflated in every month: January shows $1,223.15 instead of $752.17. And
BETWEEN '2025-01-01' AND '2025-12-31' stops at midnight on Dec 31, so December has 623 orders
instead of 634.
Fix the fan-out first by summing lines per order in a CTE. Then switch to a half-open range. The order count, the revenue and the shipping total should all match the order system afterward.
Step 2: cancellation rate per channel
The starter returns 12 rows for 3 channels. GROUP BY channel, status splits each channel into one
row per status, so the cancelled row shows 100% and every other row 0%. That is a grain bug: the
extra column makes the grouping finer than the question.
Fix the grouping and a second bug appears: // is integer division, so app’s rate reads 6 instead of
6.23. Use 100.0 * and divide with /.
Step 3: repeat rate per segment
A repeat rate of exactly 100% for both segments is impossible. The HAVING COUNT(*) >= 2 inside
the CTE removes one-time buyers before the outer query counts buyers, so numerator and denominator
are the same group. This is the WHERE versus HAVING lesson in another form: a filter applied at the
wrong step changes what the aggregate means.
Remove the HAVING. The outer FILTER (WHERE b.orders >= 2) already restricts the numerator.
Business has 253 buyers and 188 repeat buyers, consumer 1,194 and 690.
How to work through a broken pack
- For each query, say in one sentence what one output row should be. Compare with the row count.
- Rebuild one number from the simplest possible query: shipping from
ordersalone, December’s count with a half-open range, buyers with a plainCOUNT(DISTINCT customer_id). - Fix one bug, rerun, compare again. A second bug often hides behind the first.
Common mistakes
- Treating
COUNT(DISTINCT o.order_id)in step 1 as proof that the query has no fan-out. It protects the count, not the sums. - Fixing step 2’s division but not its grouping: 0% and 100% rows are still wrong.
- Moving step 3’s
HAVINGinto the outer query: that filters segments, not customers.
In SQL Server
T-SQL has no FILTER clause. Write conditional counts with CASE, which also works in DuckDB:
SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) AS cancelled_orders,
ROUND(100.0 * SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) / COUNT(*), 2)
On the job
Write down what was wrong in each query when you hand the pack back. The board will ask why last quarter’s numbers changed, and “shipping was counted once per line” is an answer they can accept.
Lantern lit!
Practised: debuggingfan outbetweengraininteger divisionhaving
- Solved
- No hints
- First run
