Joining Multiple Tables
Joins chain: each JOIN adds one more table, linked by its key to a table already in the query. A many-to-many link goes through its associative table, and a table can even join to itself.
Journeyman · T-SQL · SQL · Updated
After this lesson you can
- Join three or more tables in one query, following the keys from table to table
- Join a table to itself, with two aliases
Key takeaways
- Each
JOINadds one more table, and itsONlinks it by key to a table already in the query. - Orders and products are many-to-many, so a query that needs both joins through their associative table,
OrderDetails. - Trace the path of keys from the table you start with to the one that holds the answer, then write one
JOINper step. - A self join joins a table to itself with two aliases, such as
efor the employee andmfor the manager. - Make a self join a
LEFT JOINwhen some rows have no match, so Andrew Fuller, who reports to no one, still appears.
You can join as many tables as a question needs. Each JOIN adds one more table, and its ON links it to a table that's already in the query.
Following the keys
What has Alfreds Futterkiste ordered, and in which categories? The answer is spread over five tables:
| Table | Gives | Linked by |
|---|---|---|
Customers |
The company name | |
Orders |
The orders | CustomerId to Customers |
OrderDetails |
Each order's lines | OrderId to Orders |
Products |
Each line's product | ProductId to OrderDetails |
Categories |
Each product's category | CategoryId to Products |
OrderDetails is the associative table from Many-to-Many: it links orders and products, which are many-to-many.
SELECT c.CompanyName, o.OrderId, p.ProductName, cat.CategoryName, od.Quantity
FROM Customers AS c
INNER JOIN Orders AS o
ON c.CustomerId = o.CustomerId
INNER JOIN OrderDetails AS od
ON o.OrderId = od.OrderId
INNER JOIN Products AS p
ON od.ProductId = p.ProductId
INNER JOIN Categories AS cat
ON p.CategoryId = cat.CategoryId
WHERE c.CustomerId = 'ALFKI'
ORDER BY o.OrderId, p.ProductName;
| CompanyName | OrderId | ProductName | CategoryName | Quantity |
|---|---|---|---|---|
| Alfreds Futterkiste | 10643 | Chartreuse verte | Beverages | 21 |
| Alfreds Futterkiste | 10643 | Spegesild | Seafood | 2 |
| Alfreds Futterkiste | 10692 | Vegie-spread | Condiments | 20 |
| Alfreds Futterkiste | 10702 | Aniseed Syrup | Condiments | 6 |
| Alfreds Futterkiste | 10835 | Raclette Courdavault | Dairy Products | 15 |
(12 rows in all.) Read it as a chain: customers to their orders, orders to their lines, lines to their products, products to their categories. Each ON takes one step along the keys.
Grouping across tables
Joined tables can be grouped like any other. Sales per category, from the order lines up to the category names:
SELECT cat.CategoryName, SUM(od.UnitPrice * od.Quantity) AS Sales
FROM OrderDetails AS od
INNER JOIN Products AS p
ON od.ProductId = p.ProductId
INNER JOIN Categories AS cat
ON p.CategoryId = cat.CategoryId
GROUP BY cat.CategoryName
ORDER BY Sales DESC;
| CategoryName | Sales |
|---|---|
| Beverages | 286526.95 |
| Dairy Products | 251330.50 |
| Meat/Poultry | 178188.80 |
| Confections | 177099.10 |
| Seafood | 141623.09 |
| Condiments | 113694.75 |
| Produce | 105268.60 |
| Grains/Cereals | 100726.80 |
A table joined to itself
Each employee's ReportsTo holds the EmployeeId of their manager, another row in the same table. To show each employee next to their manager's name, join Employees to itself, with two aliases: e for the employee, m for the manager:
SELECT e.FirstName + ' ' + e.LastName AS Employee
, m.FirstName + ' ' + m.LastName AS Manager
FROM Employees AS e
LEFT JOIN Employees AS m
ON e.ReportsTo = m.EmployeeId
ORDER BY e.EmployeeId;
| Employee | Manager |
|---|---|
| Nancy Davolio | Andrew Fuller |
| Andrew Fuller | NULL |
| Janet Leverling | Andrew Fuller |
| Margaret Peacock | Andrew Fuller |
| Steven Buchanan | Andrew Fuller |
| Michael Suyama | Steven Buchanan |
(9 rows in all.) This is a self join. It's a LEFT JOIN so that Andrew Fuller, who reports to no one, still appears.
Check yourself
2 questions to try on the lesson page.
So what
Any question, however many tables it spans, is a chain of joins along the keys. Sketch the path from the table you start with to the one that holds the answer, then write one JOIN per step.