Mastering SQL Joins 1684493647
Mastering SQL Joins 1684493647
Mastering SQL Joins 1684493647
Databases
SQL is a powerful language for working with relational databases. One of the key features of SQL is the
ability to join tables together, allowing you to combine data from multiple sources into a single result
set. However, many SQL users find joins to be complex and confusing, and struggle to use them
effectively.
This book aims to demystify SQL joins and provide a comprehensive guide to querying relational
databases. Whether you're a beginner who is just starting to learn SQL, or an experienced developer
who wants to deepen your understanding of joins, this book has something for you.
We'll start by introducing the basic concepts of SQL joins, including the different types of joins and how
they work. We'll then move on to more advanced topics, such as using aggregate functions with joins,
optimizing join performance, and dealing with null values.
Throughout the book, we'll use examples and exercises to help you practice your SQL skills and build
your understanding of joins. We'll also provide tips and best practices for writing efficient and effective
SQL code.
By the end of this book, you'll be able to confidently use SQL joins to query relational databases and
solve complex data problems. Whether you're working with small datasets or large enterprise
systems, the techniques and strategies in this book will help you get the most out of your SQL
queries.
1. Inner Join:
An inner join returns only the rows that have matching values in both tables being joined. It includes
only the common values in both tables.
Example:
Consider two tables, 'students' and 'exams'. We want to query the student name and exam name for
all students who have taken an exam.
FROM students
ON students.student_id = exams.student_id;
This query will return only the rows where both the 'students' and 'exams' tables have matching
values in the 'student_id' column.
2. Left Join:
A left join returns all the rows from the left table, and the matching rows from the right table. If there
is no matching row in the right table, NULL values are returned.
Example:
Consider two tables, 'employees' and 'departments'. We want to query the name and department
name for all employees, even if they do not belong to a department.
FROM employees
ON employees.department_id = departments.department_id;
This query will return all the rows from the 'employees' table and only the matching rows from the
'departments' table. If an employee does not belong to a department, the department name will be
NULL.
3. Right Join:
A right join returns allthe rows from the right table, and the matching rows from the left table. If
there is no matching row in the left table, NULL values are returned.
Example:
Consider the same two tables as above, 'employees' and 'departments'. We want to query the name
and department name for all departments, even if they do not have any employees.
FROM employees
ON employees.department_id = departments.department_id;
This query will return all the rows from the 'departments' table and only the matching rows from the
'employees' table. If a department does not have any employees, the employee name will be NULL.
A full outer join returns all the rows from both tables, including the non-matching rows. If there is no
matching row in one table, NULL values are returned.
Example:
Consider two tables, 'students' and 'courses'. We want to query the student name and course name
for all students and courses, including those who do not have any courses or those without any
students.
FROM students
ON students.student_id = courses.student_id;
This query will return all the rows from both the 'students' and 'courses' tables, including those with
non-matching values. If a student does not have any courses or a course does not have any students,
the corresponding name will be NULL.
Now that we've coveredthe four main types of joins in SQL, here are 25 exercises about joins with
solutions and explanations:
1. Write a SQL query to display the first name, last name, and department name of all employees.
Solution:
FROM employees
ON employees.department_id = departments.department_id;
Explanation:
This query uses an inner join to combine the 'employees' and 'departments' tables on the
'department_id' column. It selects the 'first_name', 'last_name', and 'department_name' columns
from the resulting table.
2. Write a SQL query to display the first name, last name, and department name of all employees,
including those who do not belong to a department.
Solution:
FROM employees
ON employees.department_id = departments.department_id;
Explanation:
This query uses a left join to combine the 'employees' and 'departments' tables on the
'department_id' column. It selects the 'first_name', 'last_name', and 'department_name' columns
from the resulting table. If an employee does not belong to a department, the department name will
be NULL.
3. Write a SQL query to display the first name, last name, and department name of all employees,
including those whose department does not have a name.
Solution:
FROMemployees
Explanation:
This query uses a left join to combine the 'employees' and 'departments' tables on the
'department_id' column. It selects the 'first_name', 'last_name', and 'department_name' columns
from the resulting table. If an employee belongs to a department that does not have a name, the
department name will be NULL.
4. Write a SQL query to display the first name, last name, and salary of all employees, as well as the
department name for those who belong to a department.
Solution:
FROM employees
ON employees.department_id = departments.department_id;
Explanation:
This query uses a left join to combine the 'employees' and 'departments' tables on the
'department_id' column. It selects the 'first_name', 'last_name', 'salary', and 'department_name'
columns from the resulting table. If an employee does not belong to a department, the department
name will be NULL.
5. Write a SQL query to display the first name, last name, and title of all employees, as well as the
department name for those who belong to a department, and the manager name for those who have
a manager.
Solution:
SELECT e.first_name, e.last_name, e.title, d.department_name, m.first_name AS
manager_first_name, m.last_name AS manager_last_name
FROM employees e
ON e.department_id = d.department_id
ON e.manager_id = m.employee_id;
Explanation:
This query uses two left joins to combine the 'employees' and 'departments' tables on the
'department_id' column, and the 'employees' table with itself on the 'manager_id' column. It selects
the 'first_name', 'last_name', 'title', 'department_name', 'manager_first_name', and
'manager_last_name' columns from the resulting table. If an employee does not belong to a
department or does not have a manager, the corresponding values will be NULL.
6. Write a SQL query to display the first name, last name, and email of all employees, as well as the
name of their department and the name of their manager.
Solution:
FROM employees e
ON e.department_id = d.department_id
ON e.manager_id = m.employee_id;
Explanation:
This query uses two left joins to combine the 'employees' and 'departments' tables on the
'department_id' column, and the 'employees' table with itself on the 'manager_id' column. It selects
the 'first_name', 'last_name', 'email', 'department_name', 'manager_first_name', and
'manager_last_name' columns from the resulting table. If an employee does not belong to a
department or does not have a manager, the corresponding values will be NULL.
7. Write a SQL query to display the name and price of all products, as well as the name of their
category.
Solution:
FROM products p
ON p.category_id = c.category_id;
Explanation:
This query uses an inner join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selectsthe 'product_name', 'price', and 'category_name' columns from the resulting table.
It will return only the rows where both tables have matching values.
8. Write a SQL query to display the name and price of all products, as well as the name of their
category, even for products that do not have a category.
Solution:
FROM products p
ON p.category_id = c.category_id;
Explanation:
This query uses a left join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selects the 'product_name', 'price', and 'category_name' columns from the resulting table.
If a product does not have a category, the category name will be NULL.
9. Write a SQL query to display the name and price of all products, as well as the name of their
category, even for categories that do not have any products.
Solution:
ON p.category_id = c.category_id;
Explanation:
This query uses a right join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selects the 'product_name', 'price', and 'category_name' columns from the resulting table.
If a category does not have any products, the product name and price will be NULL.
10. Write aSQL query to display the name and price of all products, as well as the name of their
category, including categories that do not have any products and products that do not have a
category.
Solution:
FROM products p
ON p.category_id = c.category_id;
Explanation:
This query uses a full outer join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selects the 'product_name', 'price', and 'category_name' columns from the resulting table.
If a category does not have any products or a product does not have a category, the corresponding
values will be NULL.
11. Write a SQL query to display the name and price of all products that have a price greater than
$10.
Solution:
FROM products
Explanation:
This query selects the 'product_name' and 'price' columns from the 'products' table, but only returns
the rows where the 'price' column is greater than 10.
12. Write a SQL query to display the name and price of all products that have a price greater than $10
and belong to the 'Electronics' category.
Solution:
FROM products p
ON p.category_id = c.category_id
Explanation:
This query uses an inner join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selects the 'product_name' and 'price' columns from the resulting table, but only returns
the rows where the 'price' column is greater than 10 and the 'category_name' column is 'Electronics'.
13. Write a SQL query to display the name and price of all products that have a price greater than $10
or belong to the 'Electronics' category.
Solution:
FROM products p
ON p.category_id = c.category_id
Explanation:
This query uses a left join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selects the 'product_name' and 'price' columns from the resulting table, but only returns
the rows where the 'price' column is greater than 10 or the 'category_name' column is 'Electronics'. If
a product does not have a category, the category name will be NULL but the row will still be included
in the result set.
14. Write a SQL query to display the name and price of all products that do not belong to the
'Electronics' category.
Solution:
FROM products p
ON p.category_id = c.category_id
Explanation:
This query uses a left join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selects the 'product_name' and 'price' columns from the resulting table,but only returns
the rows where the category name is NULL (indicating that the product does not belong to a
category) or the category name is not 'Electronics'. This query ensures that all products that do not
belong to the 'Electronics' category are included in the result set.
15. Write a SQL query to display the name and price of all products that belong to the 'Electronics'
category and were added in the last 30 days.
Solution:
FROM products p
ON p.category_id = c.category_id
Explanation:
This query uses an inner join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selects the 'product_name' and 'price' columns from the resulting table, but only returns
the rows where the 'category_name' column is 'Electronics' and the 'added_date' column is within
the last 30 days. The DATEADD() function is used to subtract 30 days from the current date
(GETDATE()).
16. Write a SQL query to display the name and price of all products that were added in the last 30
days, sorted by price in descending order.
Solution:
FROM products
Explanation:
This query selects the 'product_name' and 'price' columns from the 'products' table, but only returns
the rows where the 'added_date' column is within the last 30 days. The DATEADD() function is used
to subtract 30 days from the current date (GETDATE()). The results are then sorted by price in
descending order using the ORDER BY clause with the DESC keyword.
17. Write a SQL query to display the name and price of the three most expensive products.
Solution:
FROM products
Explanation:
This query selects the 'product_name' and 'price' columns from the 'products' table, and returns only
the top 3 rows sorted by price in descending order using the TOP and ORDER BY clauses.
18. Write a SQL query to display the name and price of the cheapest product in each category.
Solution:
ON p.category_id = c.category_id
Explanation:
This query uses an inner join to combine the 'products' and 'categories' tables on the 'category_id'
column. It selects the 'product_name', 'price', and 'category_name' columns from the resulting table,
but only returns the rows where the 'price' column is theminimum price for each category. This is
achieved by using a subquery in the WHERE clause to find the minimum price for each category, and
then comparing it to the 'price' column of the 'products' table. The subquery is filtered by the
'category_id' column of the 'products' table to ensure that only the minimum price for each category
is returned.
19. Write a SQL query to display the name and price of all products that were ordered by at least one
customer, along with the number of times each product was ordered.
Solution:
FROM products p
ON p.product_id = o.product_id
Explanation:
This query uses a left join to combine the 'products' and 'order_items' tables on the 'product_id'
column. It selects the 'product_name' and 'price' columns from the 'products' table, and also counts
the number of times each product was ordered using the COUNT() function and the 'product_id'
column of the 'order_items' table. The results are grouped by 'product_name' and 'price' using the
GROUP BY clause. The HAVING clause is used to filter out products that were not ordered by any
customers.
20. Write a SQL query to display the name and email of all customers who have not placed any
orders.
Solution:
FROM customers c
ON c.customer_id = o.customer_id
Explanation:
This query uses a left join to combine the 'customers' and 'orders' tables on the 'customer_id'
column. It selects the 'customer_name' and 'email' columns from the 'customers' table, but only
returns the rows where the 'order_id' column of the 'orders' table is NULL. This ensures that only
customers who have not placed any orders are included in the result set.
21. Write a SQL query to display the name and total price of all orders, grouped by customer.
Solution:
FROM customers c
ON c.customer_id = o.customer_id
ON o.order_id = oi.order_id
GROUP BY c.customer_name;
Explanation:
This query uses two left joins to combine the 'customers', 'orders', and 'order_items' tables on their
respective keys. It selects the 'customer_name' column from the 'customers' table, and calculates the
total price of each order by multiplying the 'price' and 'quantity' columns of the 'order_items' table,
and summing the results using the SUM() function. The results are grouped by 'customer_name'
using the GROUP BY clause.
22. Write a SQL query to display the name and total price of all orders that were placed in the last
month, grouped by customer.
Solution:
FROM customers c
ON o.order_id = oi.order_id
GROUP BY c.customer_name;
Explanation:
This query uses two inner joins to combine the 'customers', 'orders', and 'order_items' tables on their
respective keys. It selects the 'customer_name' column from the 'customers' table, and calculates the
total price of each order by multiplying the 'price' and 'quantity' columns of the 'order_items' table,
and summing the results using the SUM() function. The results are grouped by 'customer_name'
using the GROUP BY clause. The WHERE clause is used to filter only the orders that were placed in the
last month, by subtracting one month from the current date (GETDATE()) using the DATEADD()
function.
23. Write a SQL query to display the name and total price of all orders that were placed by customers
who live in the same city as the store.
Solution:
FROM customers c
ON c.customer_id = o.customer_id
ON o.order_id = oi.order_id
GROUP BY c.customer_name;
Explanation:
This query uses two inner joins to combine the 'customers', 'orders', and 'order_items' tables on their
respective keys. It selects the 'customer_name' column from the 'customers' table, and calculates the
total price of each order by multiplying the 'price' and 'quantity' columns of the 'order_items' table,
and summing the results using the SUM() function. The results are grouped by 'customer_name'
using the GROUP BY clause. The WHERE clause is used to filter only the orders that were placed by
customers who live in the same city as the store with ID 1, which is selected using a subquery.
24. Write a SQL query to display the name and total price of all orders that were placed by customers
who have placed at least two orders.
Solution:
ON c.customer_id = o.customer_id
ON o.order_id = oi.order_id
GROUP BY c.customer_name;
Explanation:
This query uses two inner joins to combine the 'customers', 'orders', and 'order_items' tables on their
respective keys. It selects the 'customer_name' column from the 'customers' table, and calculates the
total price of each order by multiplying the 'price' and 'quantity' columns of the 'order_items' table,
and summing the results using the SUM() function. The results are grouped by 'customer_name'
using the GROUP BY clause. The WHERE clause is used to filter only the orders that were placed by
customers who have placed at least two orders, by selecting the 'customer_id' column from the
'orders' table, grouping by it using the GROUP BY clause, and filtering the results using the HAVING
clause.
25. Write a SQL query to display the name and total price of all orders that were placed by customers
who have never returned any products.
Solution:
FROM customers c
INNER JOIN orders o
ON c.customer_id = o.customer_id
ON o.order_id = oi.order_id
GROUP BY c.customer_name;
Explanation:
This query uses two inner joins to combine the 'customers', 'orders', and 'order_items' tables on their
respective keys. It selects the 'customer_name' column from the 'customers' table, and calculates the
total price of each order by multiplying the 'price' and 'quantity' columns of the 'order_items' table,
and summing the results using the SUM() function. The results are grouped by 'customer_name'
using the GROUP BY clause. The WHERE clause is used to filter only the orders that were placed by
customers who have never returned any products, by selecting the 'customer_id' column from the
'returns' table and using the NOT IN operator to exclude those customers from the result set.