1. Lighthouse

Level 7 · Business accounts with an unknown or friend referral

The request

From Ryan Cooper, Regional Sales Manager

“We're launching a referral program for business accounts. I want to reach out to business customers who signed up in the second half of 2024 and either came from a friend or never told us how they found us.”

Your goal

From customers, return customer_id, first_name, last_name, signup_date and referral_source for customers whose segment is 'business', whose signup_date is from 2024-07-01 through 2024-12-31, and whose referral_source is either 'friend' or missing (NULL).

  • Read from the customers tablenot done yet
  • Show exactly customer_id first_name last_name signup_date referral_sourcenot done yet
  • 23 rowsnot 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
    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
    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
    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

    This filter brings together two lessons from this chapter: missing values need IS NULL, and an OR mixed with AND needs parentheses.

    NULL is not a value you can compare

    referral_source is NULL for 666 customers: they skipped the “How did you hear about us?” question. A comparison with NULL is neither true nor false, it is unknown, and WHERE only keeps rows where the condition is true. So referral_source = NULL keeps nothing, and referral_source <> 'friend' also silently drops the NULL rows. To ask for missing values, write IS NULL; for present ones, IS NOT NULL.

    Put the OR in parentheses

    Ryan wants business accounts from late 2024, and within those, two kinds of referral. The “two kinds” part is an OR, and it must be grouped:

    SELECT COUNT(*) AS leads
    FROM customers
    WHERE segment = 'business'
      AND signup_date >= '2024-07-01'
      AND signup_date < '2025-01-01'
      AND (referral_source = 'friend' OR referral_source IS NULL);

    That counts 23 leads. Remove the parentheses and the count jumps to 203, because AND binds before OR and the query becomes “business late-2024 accounts with no source, plus every customer referred by a friend at any time”. The ticket would go to sales with consumers from 2023 on it. COUNT(*) is covered properly in chapter 4; here it is just a quick way to see the row count change.

    Common mistakes

    • Writing referral_source IN ('friend', NULL). IN compares with =, so the NULL in the list never matches. Use IN for real values and a separate IS NULL.
    • Using BETWEEN '2024-07-01' AND '2024-12-31'. On this DATE column it happens to work, but the half-open range keeps working on timestamps too, so it is the safer habit.
    • Forgetting the segment. Without it, consumer accounts make up most of the list.

    In SQL Server

    IS NULL, OR and the parentheses work exactly the same. You may see ISNULL(referral_source, '') IN ('friend', '') used as a shortcut there; it works, but it also matches real empty strings and hides the intent. The plain version reads better in every database:

    WHERE segment = 'business'
      AND signup_date >= '2024-07-01' AND signup_date < '2025-01-01'
      AND (referral_source = 'friend' OR referral_source IS NULL);

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