lesson 82 Warehouse & reporting projects · advanced
Automated star-schema quality tests
Test relationships and data quality in a star schema.
the idea
A data quality test has a name, an expectation and a failure count. Zero failures means that expectation held, not that the data is perfect. Check unique line ids, valid quantities and both dimension relationships, then gate publication on the blocking tests.
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.
dim_customer5 columns · 848 rows
| customer_keynumber · unique id | customer_idtext | contact_nametext | countrytext | regiontext |
|---|---|---|---|---|
| 1 | 12347 | Arthur Turner | Iceland | Europe |
| 2 | 12353 | Harry Turner | Bahrain | Rest of World |
| 3 | 12359 | Theo Turner | Cyprus | Europe |
| 4 | 12373 | Harry Hill | Austria | Europe |
| 5 | 12374 | Emily Hill | Austria | Europe |
| 6 | 12384 | Ava Moore | Switzerland | Europe |
- customer_keynumber · unique id
- 1
- customer_idtext
- 12347
- contact_nametext
- Arthur Turner
- countrytext
- Iceland
- regiontext
- Europe
- customer_keynumber · unique id
- 2
- customer_idtext
- 12353
- contact_nametext
- Harry Turner
- countrytext
- Bahrain
- regiontext
- Rest of World
- customer_keynumber · unique id
- 3
- customer_idtext
- 12359
- contact_nametext
- Theo Turner
- countrytext
- Cyprus
- regiontext
- Europe
- customer_keynumber · unique id
- 4
- customer_idtext
- 12373
- contact_nametext
- Harry Hill
- countrytext
- Austria
- regiontext
- Europe
- customer_keynumber · unique id
- 5
- customer_idtext
- 12374
- contact_nametext
- Emily Hill
- countrytext
- Austria
- regiontext
- Europe
- customer_keynumber · unique id
- 6
- customer_idtext
- 12384
- contact_nametext
- Ava Moore
- countrytext
- Switzerland
- regiontext
- Europe
first 6 of 848 rows · your queries use all of them
dim_product5 columns · 4,902 rows
| product_keynumber · unique id | product_idtext | descriptiontext | categorytext | pricedecimal |
|---|---|---|---|---|
| 1 | 10002 | INFLATABLE POLITICAL GLOBE | Other Gifts | 0.85 |
| 2 | 10002R | ROBOT PENCIL SHARPNER | Stationery & Gift Wrap | 5.17 |
| 3 | 10080 | GROOVY CACTUS INFLATABLE | Other Gifts | 0.39 |
| 4 | 10109 | BENDY COLOUR PENCILS | Stationery & Gift Wrap | 0.42 |
| 5 | 10120 | DOGGY RUBBER | Other Gifts | 0.21 |
| 6 | 10123C | HEARTS WRAPPING TAPE | Stationery & Gift Wrap | 0.65 |
- product_keynumber · unique id
- 1
- product_idtext
- 10002
- descriptiontext
- INFLATABLE POLITICAL GLOBE
- categorytext
- Other Gifts
- pricedecimal
- 0.85
- product_keynumber · unique id
- 2
- product_idtext
- 10002R
- descriptiontext
- ROBOT PENCIL SHARPNER
- categorytext
- Stationery & Gift Wrap
- pricedecimal
- 5.17
- product_keynumber · unique id
- 3
- product_idtext
- 10080
- descriptiontext
- GROOVY CACTUS INFLATABLE
- categorytext
- Other Gifts
- pricedecimal
- 0.39
- product_keynumber · unique id
- 4
- product_idtext
- 10109
- descriptiontext
- BENDY COLOUR PENCILS
- categorytext
- Stationery & Gift Wrap
- pricedecimal
- 0.42
- product_keynumber · unique id
- 5
- product_idtext
- 10120
- descriptiontext
- DOGGY RUBBER
- categorytext
- Other Gifts
- pricedecimal
- 0.21
- product_keynumber · unique id
- 6
- product_idtext
- 10123C
- descriptiontext
- HEARTS WRAPPING TAPE
- categorytext
- Stationery & Gift Wrap
- pricedecimal
- 0.65
first 6 of 4,902 rows · your queries use all of them
dq_sales5 columns · 2,555 rows
| line_idnumber | customer_keynumber | product_keynumber | quantitynumber | salesdecimal |
|---|---|---|---|---|
| 123027 | 467 | 2476 | 24 | 39.6 |
| 123028 | 467 | 1829 | 3 | 17.85 |
| 123029 | 467 | 428 | 4 | 15 |
| 123030 | 467 | 2725 | 6 | 17.34 |
| 123031 | 467 | 3247 | 4 | 15.8 |
| 123032 | 467 | 2573 | 2 | 19.9 |
- line_idnumber
- 123027
- customer_keynumber
- 467
- product_keynumber
- 2476
- quantitynumber
- 24
- salesdecimal
- 39.6
- line_idnumber
- 123028
- customer_keynumber
- 467
- product_keynumber
- 1829
- quantitynumber
- 3
- salesdecimal
- 17.85
- line_idnumber
- 123029
- customer_keynumber
- 467
- product_keynumber
- 428
- quantitynumber
- 4
- salesdecimal
- 15
- line_idnumber
- 123030
- customer_keynumber
- 467
- product_keynumber
- 2725
- quantitynumber
- 6
- salesdecimal
- 17.34
- line_idnumber
- 123031
- customer_keynumber
- 467
- product_keynumber
- 3247
- quantitynumber
- 4
- salesdecimal
- 15.8
- line_idnumber
- 123032
- customer_keynumber
- 467
- product_keynumber
- 2573
- quantitynumber
- 2
- salesdecimal
- 19.9
first 6 of 2,555 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 duplicated line ids. Run this. line_id should be unique; groups with COUNT(*) > 1 mean the same sale line arrived twice in the batch.the pattern
example.sqlSELECT line_id, COUNT(*) AS copies FROM dq_sales GROUP BY line_id HAVING COUNT(*) > 1 LIMIT 10;
Find facts missing a customer dimension. customer_key values with no dim_customer row are orphans—those lines fail the relationship test before publish.
step-2.sqlSELECT s.line_id, s.customer_key FROM dq_sales s LEFT JOIN dim_customer c ON c.customer_key = s.customer_key WHERE c.customer_key IS NULL LIMIT 10;
Shape one quality test query. Each named test returns one row: test name and failure count. Zero failures means that rule passed, not that the batch is perfect.
step-3.sqlSELECT 'duplicate_line_ids' AS test, COUNT(*) AS failures FROM ( SELECT line_id FROM dq_sales GROUP BY line_id HAVING COUNT(*) > 1 );
common mistake
Failure counts can overlap on one row; their sum counts rule violations, not distinct bad rows.