3. Query Multiple Tables with Joins

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 7

Query Multiple Tables with Joins

In this lab, you'll use the Transact-SQL SELECT statement to query multiple tables in
the adventureworks database. For your reference, the following diagram shows the
tables in the database (you may need to resize the pane to see them clearly).

Note: If you're familiar with the standard AdventureWorks sample database, you may
notice that in this lab we are using a simplified version that makes it easier to focus on
learning Transact-SQL syntax.

Use inner joins


An inner join is used to find related data in two tables. For example, suppose you need
to retrieve data about a product and its category from
the SalesLT.Product and SalesLT.ProductCategory tables. You can find the relevant
product category record for a product based on its ProductCategoryID field; which is a
foreign-key in the product table that matches a primary key in the product category
table.

1. Start Azure Data Studio, and create a new query (you can do this from
the File menu or on the welcome page).
2. In the new SQLQuery_… pane, use the Connect button to connect the query to
the AdventureWorks saved connection.
3. In the query editor, enter the following code:
4. SELECT SalesLT.Product.Name As ProductName,
SalesLT.ProductCategory.Name AS Category
5. FROM SalesLT.Product
6. INNER JOIN SalesLT.ProductCategory
ON SalesLT.Product.ProductCategoryID =
SalesLT.ProductCategory.ProductCategoryID;

7. Use the ⏵Run button to run the query, and and after a few seconds, review the
results, which include the ProductName from the products table and the
corresponding Category from the product category table. Because the query
uses an INNER join, any products that do not have corresponding categories,
and any categories that contain no products are omitted from the results.
8. Modify the query as follows to remove the INNER keyword, and re-run it.
9. SELECT SalesLT.Product.Name As ProductName,
SalesLT.ProductCategory.Name AS Category
10. FROM SalesLT.Product
11. JOIN SalesLT.ProductCategory
ON SalesLT.Product.ProductCategoryID =
SalesLT.ProductCategory.ProductCategoryID;

The results should be the same as before. INNER joins are the default kind of
join.

12. Modify the query to assign aliases to the tables in the JOIN clause, as shown
here:
13. SELECT p.Name As ProductName, c.Name AS Category
14. FROM SalesLT.Product AS p
15. JOIN SalesLT.ProductCategory As c
ON p.ProductCategoryID = c.ProductCategoryID;

16. Run the modified query and confirm that it returns the same results as before.
The use of table aliases can greatly simplify a query, particularly when multiple
joins must be used.
17. Replace the query with the following code, which retrieves sales order data from
the SalesLT.SalesOrderHeader, SalesLT.SalesOrderDetail,
and SalesLT.Product tables:
18. SELECT oh.OrderDate, oh.SalesOrderNumber, p.Name As ProductName,
od.OrderQty, od.UnitPrice, od.LineTotal
19. FROM SalesLT.SalesOrderHeader AS oh
20. JOIN SalesLT.SalesOrderDetail AS od
21. ON od.SalesOrderID = oh.SalesOrderID
22. JOIN SalesLT.Product AS p
23. ON od.ProductID = p.ProductID
ORDER BY oh.OrderDate, oh.SalesOrderID, od.SalesOrderDetailID;

24. Run the modified query and note that it returns data from all three tables.

Use outer joins


An outer join is used to retrieve all rows from one table, and any corresponding rows
from a related table. In cases where a row in the outer table has no corresponding rows
in the related table, NULL values are returned for the related table fields. For example,
suppose you want to retrieve a list of all customers and any orders they have placed,
including customers who have registered but never placed an order.

1. Replace the existing query with the following code:


2. SELECT c.FirstName, c.LastName, oh.SalesOrderNumber
3. FROM SalesLT.Customer AS c
4. LEFT OUTER JOIN SalesLT.SalesOrderHeader AS oh
5. ON c.CustomerID = oh.CustomerID
ORDER BY c.CustomerID;

6. Run the query and note that the results contain data for every customer. If a
customer has placed an order, the order number is shown. Customers who have
registered but not placed an order are shown with a NULL order number.

Note the use of the LEFT keyword. This identifies which of the tables in the
join is the outer table (the one from which all rows should be preserved). In this
case, the join is between the Customer and SalesOrderHeader tables, so
a LEFT join designates Customer as the outer table. Had a RIGHT join been
used, the query would have returned all records from
the SalesOrderHeader table and only matching data from
the Customer**table (in other words, all orders including those for which
there was no matching customer record). You can also use a *FULL outer
join to preserve unmatched rows from *both sides of the join (all customers,
including those who haven't placed an order; and all orders, including those with
no matching customer), though in practice this is used less frequently.

7. Modify the query to remove the OUTER keyword, as shown here:


8. SELECT c.FirstName, c.LastName, oh.SalesOrderNumber
9. FROM SalesLT.Customer AS c
10. LEFT JOIN SalesLT.SalesOrderHeader AS oh
11. ON c.CustomerID = oh.CustomerID
ORDER BY c.CustomerID;

12. Run the query and review the results, which should be the same as before. Using
the LEFT (or RIGHT) keyword automatically identifies the join as
an OUTER join.
13. Modify the query as shown below to take advantage of the fact that it identifies
non-matching rows and return only the customers who have not placed any
orders.
14. SELECT c.FirstName, c.LastName, oh.SalesOrderNumber
15. FROM SalesLT.Customer AS c
16. LEFT JOIN SalesLT.SalesOrderHeader AS oh
17. ON c.CustomerID = oh.CustomerID
18. WHERE oh.SalesOrderNumber IS NULL
ORDER BY c.CustomerID;

19. Run the query and review the results, which contain data for customers who
have not placed any orders.
20. Replace the query with the following one, which uses outer joins to retrieve data
from three tables.
21. SELECT p.Name As ProductName, oh.SalesOrderNumber
22. FROM SalesLT.Product AS p
23. LEFT JOIN SalesLT.SalesOrderDetail AS od
24. ON p.ProductID = od.ProductID
25. LEFT JOIN SalesLT.SalesOrderHeader AS oh
26. ON od.SalesOrderID = oh.SalesOrderID
ORDER BY p.ProductID;

27. Run the query and note that the results include all products, with order numbers
for any that have been purchased. This required a sequence of joins
from Product to SalesOrderDetail to SalesOrderHeader. Note that when you
join multiple tables like this, after an outer join has been specified in the join
sequence, all subsequent outer joins must be of the same direction
(LEFT or RIGHT).
28. Modify the query as shown below to add an inner join to return category
information. When mixing inner and outer joins, it can be helpful to be explicit
about the join types by using the INNER and OUTER keywords.
29. SELECT p.Name As ProductName, c.Name AS Category,
oh.SalesOrderNumber
30. FROM SalesLT.Product AS p
31. LEFT OUTER JOIN SalesLT.SalesOrderDetail AS od
32. ON p.ProductID = od.ProductID
33. LEFT OUTER JOIN SalesLT.SalesOrderHeader AS oh
34. ON od.SalesOrderID = oh.SalesOrderID
35. INNER JOIN SalesLT.ProductCategory AS c
36. ON p.ProductCategoryID = c.ProductCategoryID
ORDER BY p.ProductID;

37. Run the query and review the results, which include product names, categories,
and sales order numbers.

Use a cross join


A cross join matches all possible combinations of rows from the tables being joined. In
practice, it's rarely used; but there are some specialized cases where it is useful.

1. Replace the existing query with the following code:


2. SELECT p.Name, c.FirstName, c.LastName, c.EmailAddress
3. FROM SalesLT.Product as p
CROSS JOIN SalesLT.Customer as c;

4. Run the query and note that the results contain a row for every product and
customer combination (which might be used to create a mailing campaign in
which an indivdual advertisement for each product is emailed to each customer -
a strategy that may not endear the company to its customers!).

Use a self join


A self join isn't actually a specific kind of join, but it's a technique used to join a table to
itself by defining two instances of the table, each with its own alias. This approach can
be useful when a row in the table includes a foreign key field that references the primary
key of the same table; for example in a table of employees where an employee's
manager is also an employee, or a table of product categories where each category
might be a subcategory of another category.

1. Replace the existing query with the following code, which includes a self join
between two instances of the SalesLT.ProductCategory table (with
aliases cat and pcat):
2. SELECT pcat.Name AS ParentCategory, cat.Name AS SubCategory
3. FROM SalesLT.ProductCategory as cat
4. JOIN SalesLT.ProductCategory pcat
5. ON cat.ParentProductCategoryID = pcat.ProductCategoryID
ORDER BY ParentCategory, SubCategory;

6. Run the query and review the results, which reflect the hierarchy of parent and
sub categories.

Challenges
Now that you've seen some examples of joins, it's your turn to try retrieving data from
multiple tables for yourself.

Tip: Try to determine the appropriate queries for yourself. If you get stuck, suggested
answers are provided at the end of this lab.

Challenge 1: Generate invoice reports

Adventure Works Cycles sells directly to retailers, who must be invoiced for their
orders. You have been tasked with writing a query to generate a list of invoices to be
sent to customers.

1. Retrieve customer orders


o As an initial step towards generating the invoice report, write a query
that returns the company name from the SalesLT.Customer table, and
the sales order ID and total due from
the SalesLT.SalesOrderHeader table.
2. Retrieve customer orders with addresses
o Extend your customer orders query to include the Main Office address
for each customer, including the full street address, city, state or
province, postal code, and country or region
o Tip: Note that each customer can have multiple addressees in
the SalesLT.Address table, so the database developer has created
the SalesLT.CustomerAddress table to enable a many-to-many
relationship between customers and addresses. Your query will need to
include both of these tables, and should filter the results so that
only Main Office addresses are included.

Challenge 2: Retrieve customer data

As you continue to work with the Adventure Works customer and sales data, you must
create queries for reports that have been requested by the sales team.
1. Retrieve a list of all customers and their orders
o The sales manager wants a list of all customer companies and their
contacts (first name and last name), showing the sales order ID and total
due for each order they have placed. Customers who have not placed any
orders should be included at the bottom of the list with NULL values for
the order ID and total due.
2. Retrieve a list of customers with no address
o A sales employee has noticed that Adventure Works does not have
address information for all customers. You must write a query that
returns a list of customer IDs, company names, contact names (first name
and last name), and phone numbers for customers with no address stored
in the database.

Challenge 3: Create a product catalog

The marketing team has asked you to retrieve data for a new product catalog.

1. Retrieve product information by category


o The product catalog will list products by parent category and
subcategory, so you must write a query that retrieves the parent category
name, subcategory name, and product name fields for the catalog.

Challenge Solutions
This section contains suggested solutions for the challenge queries.

Challenge 1

1. Retrieve customer orders:


2. SELECT c.CompanyName, oh.SalesOrderID, oh.TotalDue
3. FROM SalesLT.Customer AS c
4. JOIN SalesLT.SalesOrderHeader AS oh
ON oh.CustomerID = c.CustomerID;

5. Retrieve customer orders with addresses:


6. SELECT c.CompanyName,
7. a.AddressLine1,
8. ISNULL(a.AddressLine2, '') AS AddressLine2,
9. a.City,
10. a.StateProvince,
11. a.PostalCode,
12. a.CountryRegion,
13. oh.SalesOrderID,
14. oh.TotalDue
15. FROM SalesLT.Customer AS c
16. JOIN SalesLT.SalesOrderHeader AS oh
17. ON oh.CustomerID = c.CustomerID
18. JOIN SalesLT.CustomerAddress AS ca
19. ON c.CustomerID = ca.CustomerID
20. JOIN SalesLT.Address AS a
21. ON ca.AddressID = a.AddressID
WHERE ca.AddressType = 'Main Office';

Challenge 2

1. Retrieve a list of all customers and their orders:


2. SELECT c.CompanyName, c.FirstName, c.LastName,
3. oh.SalesOrderID, oh.TotalDue
4. FROM SalesLT.Customer AS c
5. LEFT JOIN SalesLT.SalesOrderHeader AS oh
6. ON c.CustomerID = oh.CustomerID
ORDER BY oh.SalesOrderID DESC;

7. Retrieve a list of customers with no address:


8. SELECT c.CompanyName, c.FirstName, c.LastName, c.Phone
9. FROM SalesLT.Customer AS c
10. LEFT JOIN SalesLT.CustomerAddress AS ca
11. ON c.CustomerID = ca.CustomerID
WHERE ca.AddressID IS NULL;

Challenge 3

1. Retrieve product information by category:


2. SELECT pcat.Name AS ParentCategory, cat.Name AS SubCategory,
prd.Name AS ProductName
3. FROM SalesLT.ProductCategory pcat
4. JOIN SalesLT.ProductCategory as cat
5. ON pcat.ProductCategoryID = cat.ParentProductCategoryID
6. JOIN SalesLT.Product as prd
7. ON prd.ProductCategoryID = cat.ProductCategoryID
ORDER BY ParentCategory, SubCategory, ProductName;

Return to Microsoft Learn

1. When you've finished the exercise, complete the knowledge check in Microsoft
Learn.
2. When the link above opens in another browser tab, return to this one to end the lab
environment.

You might also like