1. Lighthouse

Level 8 · Boss: the annual business review

The request

From Catherine Hale, Chief Executive Officer

“For the 2025 annual review I want three slides: how each sales channel grew against 2024, the two best products per category in Q4, and how much of each quarter's revenue came from returning customers.”

Your goal

Step 1 of 3. Return one row per channel with: channel, revenue_2024 (net revenue of orders placed in 2024, rounded to 2), revenue_2025 (same for 2025, rounded to 2), yoy_growth_pct ((revenue_2025 - revenue_2024) / revenue_2024 * 100, rounded to 1) and share_2025_pct (the channel's share of total 2025 net revenue across all channels, times 100, rounded to 1). Sort by revenue_2025 descending.

  • Read from the orders tablenot done yet
  • Read from the order_items tablenot done yet
  • Show exactly channel revenue_2024 revenue_2025 yoy_growth_pct share_2025_pctnot done yet

Step 1 · your query

SQL

Loading the editor…

    ResultPreview of orders · press Run to see yours
    Preview of orders
    order_idcustomer_idorder_datestatuschannel
    10011252023-01-01 20:51:19completedweb
    10021562023-01-02 07:58:46completedweb
    1003222023-01-02 10:25:27completedmarketplace
    1004482023-01-02 11:21:51completedmarketplace

    Mote checks your result

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

    Step 2 · your query

    SQL

    Loading the editor…

      ResultPreview of products · press Run to see yours
      Preview of products
      product_idnamecategorysubcategoryunit_price
      101Vale Velvet LoveseatFurnitureSofas1659.00
      102Alder Oak Coffee TableFurnitureTables919.00
      103Orchard Rattan Dining ChairFurnitureChairs789.00
      104Upland Oak BookcaseFurnitureStorage429.00

      Mote checks your result

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

      Step 3 · your query

      SQL

      Loading the editor…

        ResultPreview of orders · press Run to see yours
        Preview of orders
        order_idcustomer_idorder_datestatuschannel
        10011252023-01-01 20:51:19completedweb
        10021562023-01-02 07:58:46completedweb
        1003222023-01-02 10:25:27completedmarketplace
        1004482023-01-02 11:21:51completedmarketplace

        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.

        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
        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
        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
        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
        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

        An annual business review is a handful of analytics patterns placed side by side. This boss asks for three of them, and each has one decision that makes it right or wrong.

        Step 1: growth and share by channel

        Put both years on the same row with conditional aggregation, so the growth is a simple column expression:

        SUM(CASE WHEN o.order_date >= '2024-01-01' AND o.order_date < '2025-01-01'
                 THEN i.quantity * i.unit_price * (1 - i.discount_pct / 100.0) END) AS revenue_2024

        The share of 2025 needs the grand total on every row: SUM(revenue_2025) OVER (). The answer is a striking slide: the app grew 53.2% and is now the largest channel (43.3% of 2025 revenue), while web shrank 7.2%. Total growth would have hidden that shift.

        Step 2: two products per category

        Here the brief says exactly two per category, so ROW_NUMBER() with a product_id tie-breaker is the right function, unlike the ties-included ranking earlier in the chapter. Watch for close calls: in Textiles the Bramble Percale Quilt beat the Delancey Cashmere-Blend Duvet Cover by under $50 in Q4 2025, and in Decor the top two are $94 apart. On a slide, a margin that thin deserves a footnote.

        Step 3: first-order vs repeat revenue

        “Is the business built on returning customers?” Number every customer’s completed orders over all history, then look at 2025:

        ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date, order_id) AS order_number

        An order with order_number = 1 is that customer’s first ever. Everything else is repeat revenue. At Harbor & Pine, 86% to 91% of each 2025 quarter’s revenue came from repeat orders. That is the signature of a mature customer base: most customers placed their first order before 2025.

        The order of operations is the whole point. Number first, filter second. If you filter orders to 2025 inside the CTE, a customer who first bought in 2023 gets order_number = 1 on their first 2025 order, and repeat revenue is badly understated.

        Common mistakes

        • Two separate queries for 2024 and 2025 joined afterwards: more code, more places for the filters to differ.
        • LIMIT for top N per group. It limits the whole result, not each category.
        • Filtering before numbering in step 3.

        In SQL Server

        The CASE-based sums work unchanged; SUM(...) OVER () and ROW_NUMBER() too. Replace DATE_TRUNC('quarter', order_date) with DATETRUNC(quarter, order_date) (2022+) or DATEFROMPARTS(YEAR(order_date), (DATEPART(quarter, order_date) - 1) * 3 + 1, 1). To keep only the top 2 without QUALIFY, filter the ranked CTE in the outer query, as here.

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