lesson 71 Warehouse & reporting projects · advanced
Bronze: inspect raw data before cleaning
Inspect incoming records before making cleaning decisions.
the idea
Bronze keeps source records exactly as received so every later step can be traced back. Before writing cleaning rules, profile the raw data: missing and untrimmed keys, repeated versions of the same entity, text that should be numbers, and dates that do not parse. Profiling describes problems; it does not fix or delete anything.
Dataset: Retail
The tables the challenges use, with their first 6 rows. Under each column name: the kind of value it holds, and which table it links to.
bronze_customers4 columns · 1,689 rows
| raw_idtext | nametext | countrytext | updated_atdate & time |
|---|---|---|---|
| 15600 | Amelia Smith | GB | 2010-04-25 09:00:00 |
| 15600 | Amelia Smith | united kingdom | 2010-07-01 09:00:00 |
| 15600 | Amelia Smith | United Kingdom | 2011-07-01 09:00:00 |
| 17600 | Amelia Smith | UK | 2011-11-22 09:00:00 |
| 18000 | Amelia Smith | United Kingdom | 2010-05-24 09:00:00 |
| 12420 | Amelia Jones | Cyprus | 2011-10-07 09:00:00 |
- raw_idtext
- 15600
- nametext
- Amelia Smith
- countrytext
- GB
- updated_atdate & time
- 2010-04-25 09:00:00
- raw_idtext
- 15600
- nametext
- Amelia Smith
- countrytext
- united kingdom
- updated_atdate & time
- 2010-07-01 09:00:00
- raw_idtext
- 15600
- nametext
- Amelia Smith
- countrytext
- United Kingdom
- updated_atdate & time
- 2011-07-01 09:00:00
- raw_idtext
- 17600
- nametext
- Amelia Smith
- countrytext
- UK
- updated_atdate & time
- 2011-11-22 09:00:00
- raw_idtext
- 18000
- nametext
- Amelia Smith
- countrytext
- United Kingdom
- updated_atdate & time
- 2010-05-24 09:00:00
- raw_idtext
- 12420
- nametext
- Amelia Jones
- countrytext
- Cyprus
- updated_atdate & time
- 2011-10-07 09:00:00
first 6 of 1,689 rows · your queries use all of them
bronze_sales6 columns · 2,526 rows
| row_idnumber · unique id | customer_idtext | product_idtext | quantitytext | salestext | order_datedate |
|---|---|---|---|---|---|
| 123027 | 15687 | 23301 | 24 | 39.60 | 2011-12-01 |
| 123028 | 15687 | 22623 | 3 | 17.85 | 2011-12-01 |
| 123029 | 15687 | 20970 | 4 | 15.00 | 2011-12-01 |
| 123030 | 15687 | 23562 | 6 | 17.34 | 2011-12-01 |
| 123031 | 15687 | 71477 | 4 | 15.80 | 2011-12-01 |
| 123032 | 15687 | 23407 | 2 | 19.90 | 2011-12-01 |
- row_idnumber · unique id
- 123027
- customer_idtext
- 15687
- product_idtext
- 23301
- quantitytext
- 24
- salestext
- 39.60
- order_datedate
- 2011-12-01
- row_idnumber · unique id
- 123028
- customer_idtext
- 15687
- product_idtext
- 22623
- quantitytext
- 3
- salestext
- 17.85
- order_datedate
- 2011-12-01
- row_idnumber · unique id
- 123029
- customer_idtext
- 15687
- product_idtext
- 20970
- quantitytext
- 4
- salestext
- 15.00
- order_datedate
- 2011-12-01
- row_idnumber · unique id
- 123030
- customer_idtext
- 15687
- product_idtext
- 23562
- quantitytext
- 6
- salestext
- 17.34
- order_datedate
- 2011-12-01
- row_idnumber · unique id
- 123031
- customer_idtext
- 15687
- product_idtext
- 71477
- quantitytext
- 4
- salestext
- 15.80
- order_datedate
- 2011-12-01
- row_idnumber · unique id
- 123032
- customer_idtext
- 15687
- product_idtext
- 23407
- quantitytext
- 2
- salestext
- 19.90
- order_datedate
- 2011-12-01
first 6 of 2,526 rows · your queries use all of them
worked example
Run these steps in order to see the idea before you write your own query. The step marked “the pattern” is what the challenges ask for. Running the example does not count toward progress.
Find broken customer keys. Run this. Some raw_id values are missing or have extra spaces—those would fail later joins if you did not clean them in Silver.the pattern
example.sqlSELECT raw_id, name, country, updated_at FROM bronze_customers WHERE raw_id IS NULL OR TRIM(raw_id) = '' OR raw_id <> TRIM(raw_id) LIMIT 20;
Find quantities that are not plain numbers. Bronze keeps source text as-is. You will see empty quantities, signs, and unit suffixes that Gold must reject or parse.
step-2.sqlSELECT row_id, quantity FROM bronze_sales WHERE TRIM(quantity) = '' OR TRIM(quantity) GLOB '*[^0-9]*' LIMIT 20;
Profile country before cleaning. One summary row counts missing countries and how many distinct spellings appear—profiling describes problems without changing Bronze.
step-3.sqlSELECT COUNT(*) AS rows, SUM(country IS NULL OR TRIM(country) = '') AS missing_country, COUNT(DISTINCT country) AS raw_spellings, COUNT(DISTINCT UPPER(TRIM(country))) AS normalized_spellings FROM bronze_customers;
common mistake
date(order_date) IS NULL catches impossible and badly formatted dates, but a NULL order_date is also NULL; decide whether that is a separate problem.