lesson 21 Joins & sets · intermediate
Revenue across tables
Calculate revenue while joining orders and related records.
the idea
Revenue lives at the line grain: quantity × unit_price. Join lines to their orders for date and type, and to products and categories for labels, then aggregate at the grain the question asks for. Cancellation lines carry negative quantities, so summing all lines gives net sales.
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.
orders6 columns · 6,722 rows
| order_idnumber · unique id | invoice_notext | customer_idnumber · links to customers | ordered_atdate & time | countrytext | order_typetext |
|---|---|---|---|---|---|
| 1 | 489438 | 18102 | 2009-12-01 09:24:00 | United Kingdom | sale |
| 2 | 489517 | 16329 | 2009-12-01 11:34:00 | United Kingdom | sale |
| 3 | C489528 | 16714 | 2009-12-01 11:50:00 | United Kingdom | cancellation |
| 4 | 489529 | 17984 | 2009-12-01 11:51:00 | United Kingdom | sale |
| 5 | 489532 | 13394 | 2009-12-01 11:58:00 | United Kingdom | sale |
| 6 | 489540 | 12913 | 2009-12-01 12:18:00 | United Kingdom | sale |
- order_idnumber · unique id
- 1
- invoice_notext
- 489438
- customer_idnumber · links to customers
- 18102
- ordered_atdate & time
- 2009-12-01 09:24:00
- countrytext
- United Kingdom
- order_typetext
- sale
- order_idnumber · unique id
- 2
- invoice_notext
- 489517
- customer_idnumber · links to customers
- 16329
- ordered_atdate & time
- 2009-12-01 11:34:00
- countrytext
- United Kingdom
- order_typetext
- sale
- order_idnumber · unique id
- 3
- invoice_notext
- C489528
- customer_idnumber · links to customers
- 16714
- ordered_atdate & time
- 2009-12-01 11:50:00
- countrytext
- United Kingdom
- order_typetext
- cancellation
- order_idnumber · unique id
- 4
- invoice_notext
- 489529
- customer_idnumber · links to customers
- 17984
- ordered_atdate & time
- 2009-12-01 11:51:00
- countrytext
- United Kingdom
- order_typetext
- sale
- order_idnumber · unique id
- 5
- invoice_notext
- 489532
- customer_idnumber · links to customers
- 13394
- ordered_atdate & time
- 2009-12-01 11:58:00
- countrytext
- United Kingdom
- order_typetext
- sale
- order_idnumber · unique id
- 6
- invoice_notext
- 489540
- customer_idnumber · links to customers
- 12913
- ordered_atdate & time
- 2009-12-01 12:18:00
- countrytext
- United Kingdom
- order_typetext
- sale
first 6 of 6,722 rows · your queries use all of them
order_items7 columns · 125,613 rows
| order_item_idnumber · unique id | order_idnumber · links to orders | line_numbernumber | stock_codetext · links to products | descriptiontext | quantitynumber | unit_pricedecimal |
|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 21329 | DINOSAURS WRITING SET | 28 | 0.98 |
| 2 | 1 | 2 | 21252 | SET OF MEADOW FLOWER STICKERS | 30 | 1.69 |
| 3 | 1 | 3 | 21100 | CHARLIE AND LOLA CHARLOTTE BAG | 30 | 1.15 |
| 4 | 1 | 4 | 21033 | JUMBO BAG CHARLIE AND LOLA TOYS | 30 | 2 |
| 5 | 1 | 5 | 20711 | JUMBO BAG TOYS | 60 | 1.3 |
| 6 | 1 | 6 | 21410 | COUNTRY COTTAGE DOORSTOP GREEN | 32 | 2.5 |
- order_item_idnumber · unique id
- 1
- order_idnumber · links to orders
- 1
- line_numbernumber
- 1
- stock_codetext · links to products
- 21329
- descriptiontext
- DINOSAURS WRITING SET
- quantitynumber
- 28
- unit_pricedecimal
- 0.98
- order_item_idnumber · unique id
- 2
- order_idnumber · links to orders
- 1
- line_numbernumber
- 2
- stock_codetext · links to products
- 21252
- descriptiontext
- SET OF MEADOW FLOWER STICKERS
- quantitynumber
- 30
- unit_pricedecimal
- 1.69
- order_item_idnumber · unique id
- 3
- order_idnumber · links to orders
- 1
- line_numbernumber
- 3
- stock_codetext · links to products
- 21100
- descriptiontext
- CHARLIE AND LOLA CHARLOTTE BAG
- quantitynumber
- 30
- unit_pricedecimal
- 1.15
- order_item_idnumber · unique id
- 4
- order_idnumber · links to orders
- 1
- line_numbernumber
- 4
- stock_codetext · links to products
- 21033
- descriptiontext
- JUMBO BAG CHARLIE AND LOLA TOYS
- quantitynumber
- 30
- unit_pricedecimal
- 2
- order_item_idnumber · unique id
- 5
- order_idnumber · links to orders
- 1
- line_numbernumber
- 5
- stock_codetext · links to products
- 20711
- descriptiontext
- JUMBO BAG TOYS
- quantitynumber
- 60
- unit_pricedecimal
- 1.3
- order_item_idnumber · unique id
- 6
- order_idnumber · links to orders
- 1
- line_numbernumber
- 6
- stock_codetext · links to products
- 21410
- descriptiontext
- COUNTRY COTTAGE DOORSTOP GREEN
- quantitynumber
- 32
- unit_pricedecimal
- 2.5
first 6 of 125,613 rows · your queries use all of them
categories3 columns · 17 rows
| category_idnumber · unique id | category_nametext | departmenttext |
|---|---|---|
| 1 | Christmas & Seasonal | Seasonal |
| 2 | Candles & Lighting | Home |
| 3 | Kitchen & Dining | Home |
| 4 | Home Decor | Home |
| 5 | Storage & Organisation | Home |
| 6 | Bags & Accessories | Fashion |
- category_idnumber · unique id
- 1
- category_nametext
- Christmas & Seasonal
- departmenttext
- Seasonal
- category_idnumber · unique id
- 2
- category_nametext
- Candles & Lighting
- departmenttext
- Home
- category_idnumber · unique id
- 3
- category_nametext
- Kitchen & Dining
- departmenttext
- Home
- category_idnumber · unique id
- 4
- category_nametext
- Home Decor
- departmenttext
- Home
- category_idnumber · unique id
- 5
- category_nametext
- Storage & Organisation
- departmenttext
- Home
- category_idnumber · unique id
- 6
- category_nametext
- Bags & Accessories
- departmenttext
- Fashion
first 6 of 17 rows · your queries use all of them
products6 columns · 5,304 rows
| stock_codetext · unique id | descriptiontext | category_idnumber · links to categories | list_pricedecimal | first_sold_atdate & time | is_merchandisenumber |
|---|---|---|---|---|---|
| 10002 | INFLATABLE POLITICAL GLOBE | 17 | 0.85 | 2009-12-01 09:08:00 | 1 |
| 10002R | ROBOT PENCIL SHARPNER | 8 | 5.17 | 2009-12-02 14:43:00 | 1 |
| 10080 | GROOVY CACTUS INFLATABLE | 17 | 0.39 | 2009-12-02 16:02:00 | 1 |
| 10109 | BENDY COLOUR PENCILS | 8 | 0.42 | 2009-12-03 12:31:00 | 1 |
| 10120 | DOGGY RUBBER | 17 | 0.21 | 2009-12-01 16:17:00 | 1 |
| 10123C | HEARTS WRAPPING TAPE | 8 | 0.65 | 2009-12-01 14:28:00 | 1 |
- stock_codetext · unique id
- 10002
- descriptiontext
- INFLATABLE POLITICAL GLOBE
- category_idnumber · links to categories
- 17
- list_pricedecimal
- 0.85
- first_sold_atdate & time
- 2009-12-01 09:08:00
- is_merchandisenumber
- 1
- stock_codetext · unique id
- 10002R
- descriptiontext
- ROBOT PENCIL SHARPNER
- category_idnumber · links to categories
- 8
- list_pricedecimal
- 5.17
- first_sold_atdate & time
- 2009-12-02 14:43:00
- is_merchandisenumber
- 1
- stock_codetext · unique id
- 10080
- descriptiontext
- GROOVY CACTUS INFLATABLE
- category_idnumber · links to categories
- 17
- list_pricedecimal
- 0.39
- first_sold_atdate & time
- 2009-12-02 16:02:00
- is_merchandisenumber
- 1
- stock_codetext · unique id
- 10109
- descriptiontext
- BENDY COLOUR PENCILS
- category_idnumber · links to categories
- 8
- list_pricedecimal
- 0.42
- first_sold_atdate & time
- 2009-12-03 12:31:00
- is_merchandisenumber
- 1
- stock_codetext · unique id
- 10120
- descriptiontext
- DOGGY RUBBER
- category_idnumber · links to categories
- 17
- list_pricedecimal
- 0.21
- first_sold_atdate & time
- 2009-12-01 16:17:00
- is_merchandisenumber
- 1
- stock_codetext · unique id
- 10123C
- descriptiontext
- HEARTS WRAPPING TAPE
- category_idnumber · links to categories
- 8
- list_pricedecimal
- 0.65
- first_sold_atdate & time
- 2009-12-01 14:28:00
- is_merchandisenumber
- 1
first 6 of 5,304 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.
Calculate each line’s amount. Run this. quantity × unit_price is line revenue; cancellations use negative quantity.
step-1.sqlSELECT i.order_item_id, o.order_type, i.quantity, i.unit_price, i.quantity * i.unit_price AS amount FROM orders o JOIN order_items i ON i.order_id = o.order_id WHERE o.ordered_at >= '2011-12-09';
Sum amounts by order type. Run this. GROUP BY order_type totals line amounts separately for sales and cancellations.the pattern
example.sqlSELECT o.order_type, ROUND(SUM(i.quantity * i.unit_price), 2) AS amount FROM orders o JOIN order_items i ON i.order_id = o.order_id GROUP BY o.order_type;
common mistake
Joining before aggregating is safe only when each line matches at most one row in every joined table. Joining a one-to-many table (such as payments) would repeat line amounts.