The request

From Jessica Turner, Merchandising Manager
Your goal
Keep the supplier_feed CTE from the starter. Convert product_id_text to an INTEGER and cost_text to a DECIMAL(10,2) (remove '$' and ',' and spaces first; text that is not a number becomes NULL). Join to products on product_id, which drops feed rows whose id is not a valid product. Return product_id, name, unit_cost (current, from products), supplier_cost (the converted feed cost) and cost_change (supplier_cost minus unit_cost, rounded to 2). Sort by product_id.
- Read from the
productstablenot done yet - Show exactly
product_idnameunit_costsupplier_costcost_changenot done yet - 10 rows, sorted as askednot done yet
Your query
Loading the editor…
Reference solution
| product_id | name | category | subcategory | unit_price |
|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 |
Mote checks your result
Press Run. Each row that matches the goal becomes a firefly in your lantern.
What Jessica gets, and why
Tables
Harbor & Pine store data, ready to query.
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 |
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 |
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
Numbers typed into a spreadsheet are text until you convert them: '$1,012.50', ' 5.10 ', 'n/a'.
Summing or comparing them as text is meaningless, so the first step with any pasted file is to cast
each column to its real type.
CAST and TRY_CAST
CAST(x AS type) converts or fails. One bad value and the whole query errors:
SELECT CAST('$219.00' AS DECIMAL(10, 2)); -- Conversion Error
TRY_CAST(x AS type) converts or returns NULL. That is what you want for cleaning, because you can
then count and inspect the NULLs instead of hunting for the row that broke the query.
Before casting, remove the formatting a human added:
TRY_CAST(REPLACE(REPLACE(TRIM(cost_text), '$', ''), ',', '') AS DECIMAL(10, 2))
'$1,012.50' becomes '1012.50' and then the number 1012.50. 'n/a' and 'TBD' become NULL. DuckDB’s
cast already tolerates spaces around a number, but trimming first makes the intent clear and works in
every database.
Reading the result
In the task, the Vale Velvet Loveseat (101) has no current unit_cost, so its cost_change is NULL
even though the supplier quoted $1,012.50. The Oakley Jute Knit Throw (162) and the Elm Brass Floor
Mirror (190) have a current cost but no usable quote. The row '21x' never reaches the result: its id
does not convert, so the join drops it. That silent drop is worth reporting back to the supplier.
Timestamps to dates
Casting is not only for text. orders.order_date is a TIMESTAMP, 2025-10-31 12:05:25 for order
11500. CAST(order_date AS DATE) gives 2025-10-31, which is what you group or join on when the
question is “per day”. Comparing a timestamp to a date-only value matches midnight only.
Common mistakes
- One REPLACE too few.
TRY_CAST('1,012.50' AS DECIMAL(10,2))is NULL. A forgotten comma quietly turns every price above $999 into NULL. - Casting to INTEGER for money. Cents get rounded away. Use
DECIMAL(10, 2). - Not counting the NULLs. After a TRY_CAST, run
COUNT(*) - COUNT(supplier_cost)to see how many values failed.
Dialects and SQL Server
BigQuery spells it SAFE_CAST, Snowflake has TRY_CAST and TRY_TO_NUMBER, Postgres has no safe cast
(filter with a regex first). SQL Server has TRY_CAST, TRY_CONVERT, and TRY_PARSE, which
understands a culture’s currency format:
SELECT TRY_CONVERT(DECIMAL(10, 2), REPLACE(REPLACE(cost_text, '$', ''), ',', '')) AS supplier_cost,
TRY_PARSE('$1,012.50' AS MONEY USING 'en-US') AS parsed_money; Lantern lit!
Practised: try castcastreplacetype conversiondata cleaning
- Solved
- No hints
- First run
