Joins on TPC-H

In this lab you will write outer joins, self joins, and set operations on the tpch database.
TPC-H is a benchmark database for a wholesaler: customers place orders, each order has line items, and each line item is a part bought from a supplier.
Keep the TPC-H Schema open while you work.
You will submit one file, joins.sql, with your query for each question.
Answer each question in a -- comment next to the query it is about; those answers are what gets graded.
Most questions tell you how many rows to expect, so you can check your own work.
Steps 1–5 are required; Step 6 is if you have time.
Step 1: Set up
Start your SSH tunnel, open pgAdmin, and click the tpch database under your server.
Then open the Query Tool on it.
tpch is read-only, so nothing you run today can change it.
Download joins.sql and open it in the Query Tool (the folder icon, or Ctrl+O). It has a heading for every question; write each query under its heading. To run one query, highlight it and press F5. pgAdmin shows the number of rows under the result, which is how you check most answers today.
Note the following about the schema:
- Every column has a prefix from its table, so the NAME column of
partisp_name, and that ofsupplieriss_name. Two tables never share a column name, so you rarely need an alias likec.c_name. lineitemhas six million rows, andordershas one and a half million. AddLIMIT 10while you work on a query, and remove it when you are done. If a query runs for more than about 10 seconds, cancel it (the stop button) and look for a missing join condition.
Write these warmup queries:
- Every nation with the name of its region, ordered by region and then nation. (25 rows)
- The name and phone number of every customer in CANADA whose account balance is over 9990. (9 rows)
Compare the first two digits of each phone number with CANADA's
n_nationkey. What do they tell you?
Step 2: Outer joins
- For customers 1 through 10, show
c_custkey,c_name, and the number of orders each one placed. Use an innerJOIN. (7 rows) Then change it to aLEFT JOIN. (10 rows) Which customers have no orders, and what pattern do you see in their keys? - Change
count(o_orderkey)tocount(*). Which rows change, and why? - Every customer who has never placed an order:
c_custkeyandc_name. (50,004 rows) Which column did you test withIS NULL, and why that one? - The number of customers with no orders, in each market segment (
c_mktsegment). (5 rows; HOUSEHOLD has 10,161) - Rewrite Question 1 with a
RIGHT JOIN, so that it returns the same 10 rows. What did you have to change besides the keyword?
From the slides
Question 1 is on slide 5 and slide 6, Question 2 is slide 9, and Question 3 is slide 8.
Step 3: ON vs. WHERE
- For customers 1 through 10, the number of orders each one placed in 1998, including the customers who placed none.
First put the date condition in the
WHEREclause. (4 rows) Then move it into theONclause. (10 rows; customers 7, 8, and 10 have 2 each) Explain why the first version lost six customers. - For customers 1 through 10, the total quantity (
l_quantity) of all the line items they ever ordered. Joincustomer,orders, andlineitem, starting withLEFT JOIN ordersand then a plainJOIN lineitem. How many rows, and which customers are missing? Fix it so that all 10 appear. (customer 10 has 2012.00) - In the fixed version, customers 3, 6, and 9 have a total of
NULL. Wrap the sum incoalesce(sum(l_quantity), 0)to show 0 instead. Is 0 orNULLthe better answer here?
From the slides
Question 1 is slide 10, and Question 2 is slide 11.
coalesce(a, b) returns a, unless a is NULL, in which case it returns b.
Step 4: Self joins
- The nations in the same region as JAPAN, not including JAPAN itself. (4 rows)
Use two aliases for
nation, such asn1for JAPAN andn2for the others. - Every pair of nations in the same region, with the region's name, listing each pair only once. (50 rows)
Before you run it, predict how many rows you would get with
<>instead of<, and with no condition on the keys at all. Then check your predictions.
From the slides
Question 2 is the query on slide 12.
Step 5: Set operations
- One contact list of the customers in CANADA with an account balance over 9990, and the suppliers in CANADA with an account balance over 9900.
Show the name, the phone number, and a third column that says
customerorsupplier, ordered by name. (12 rows) - The customers who have never placed an order, using
EXCEPTinstead of a join. (50,004 rows, as in Step 2) Then addc_nameto the firstSELECT. What error do you get, and why? - The customers (
o_custkey) who placed an order in 1997 and in 1998, usingINTERSECT. (62,637 rows) Then change it toEXCEPT,UNION, andUNION ALL, and write down the number of rows for each. Why isUNION ALLso much bigger thanUNION? - 86,680 customers ordered in 1997, and 71,057 ordered in 1998.
Use those two numbers and your
INTERSECTcount to explain theUNIONcount. Then swap the two queries around theEXCEPT. Do you get the same answer?
For the dates, either o_orderdate BETWEEN '1997-01-01' AND '1997-12-31' or extract(year FROM o_orderdate) = 1997 works.
From the slides
Question 1 is the query on slide 13, Question 2 is slide 15, and Question 3 is the table on slide 14.
Step 6: Harder "none" questions (if time)
The suppliers in GERMANY who supply no part of size 50. There are 396 suppliers in GERMANY.
- Write it with
EXCEPT: the German suppliers' keys, except the keys of suppliers who supply a part of size 50. (84 rows) - Now try it with outer joins, all in one
FROMclause:This returns 31,099 rows, not 84. What do those rows have in common?FROM supplier JOIN nation ON n_nationkey = s_nationkey LEFT JOIN partsupp ON ps_suppkey = s_suppkey LEFT JOIN part ON p_partkey = ps_partkey AND p_size = 50 WHERE n_name = 'GERMANY' AND p_partkey IS NULL - Fix it by joining
partsuppandparttogether first, and then outer-joining the result:Which version,LEFT JOIN (partsupp JOIN part ON p_partkey = ps_partkey AND p_size = 50) ON ps_suppkey = s_suppkeyEXCEPTor the join, would you rather read? Which one lets you shows_nametoo?
On Tuesday, we'll write this a third way, with a subquery.
Submission
Submit your file joins.sql via Gradescope by the end of the day.
The autograder only checks that the file has the queries and comments the steps ask for; it does not run your queries.
Your answers to the questions are graded by hand.