The LEFT JOIN is a powerful SQL join operation that combines rows from two or more tables, displaying all entries from the primary (left) table along with matching entries from the secondary (right) table. Unmatched rows from the secondary table are indicated by NULL values, clearly identifying missing relationships or incomplete data. Analytics engineers rely heavily on LEFT JOIN to analyze data completeness, detect gaps, and build comprehensive reports that reflect both matched and unmatched records.
This tutorial, “SQL Tasks – LEFT JOIN,” helps you master LEFT JOIN through engaging scenarios, enabling you to understand how relational data is interconnected and how to manage incomplete data effectively.
🚀 Jump Right to Exercise Tasks: SQL Tasks – LEFT JOIN
Understanding LEFT JOIN Basics
Imagine you’re managing a school database. You want to see all students, including those who haven’t enrolled in any classes yet. A LEFT JOIN
helps you retrieve every student’s name along with their enrolled class titles, clearly showing which students haven’t enrolled in any classes.
Practical Example
SELECT students.student_name, enrollments.course_title
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id;
Example Solution Explained:
The query lists every student from the “students” table and checks for matching enrollment data. If a student isn’t enrolled in any class, the “course_title” will show as NULL, making it easy to identify who still needs to enroll.
Example Output:
student_name | course_title
-------------|-------------
Jane Doe | Biology
John Smith | NULL
Key Takeaways:
- LEFT JOIN includes all records from the primary table, even unmatched ones.
- Helps identify missing relational data quickly.
Finding Unmatched Data Records
Suppose you’re managing customer orders. You want to find out which customers haven’t placed any orders yet. Using LEFT JOIN, you can quickly spot these customers and follow up with targeted marketing.
Practical Example
SELECT customers.customer_name, orders.order_id
FROM customers
LEFT JOIN orders ON customers.customer_id = orders.customer_id
WHERE orders.order_id IS NULL;
Example Solution Explained:
This query retrieves all customer names, then filters for those without any matching order IDs. Customers listed with NULL order IDs haven’t made purchases yet, indicating potential opportunities.
Example Output:
customer_name | order_id
--------------|---------
Alice Brown | NULL
David Clark | NULL
Key Takeaways:
- Quickly identifies unmatched entries using LEFT JOIN and WHERE.
- Useful for targeted customer outreach and relationship management.
Filtering with LEFT JOIN
Consider you’re reviewing employee assignments. You need a report showing all employees, highlighting those hired after a specific date, including those without a department assignment.
Practical Example
SELECT employees.employee_name, departments.department_name
FROM employees
LEFT JOIN departments ON employees.department_id = departments.department_id
WHERE employees.hire_date > '2022-01-01';
Example Solution Explained:
The query returns all employees hired after January 1, 2022, along with their department names. Employees with NULL department entries haven’t been assigned yet, allowing easy identification for follow-up.
Example Output:
employee_name | department_name
--------------|----------------
Laura Green | Finance
Tom Harris | NULL
Key Takeaways:
- Combining LEFT JOIN and WHERE enables precise filtering.
- Efficiently highlights gaps in departmental assignments.
Creating Complete Data Reports
Imagine you’re auditing product inventory. A LEFT JOIN helps you list every product along with inventory counts, clearly marking items without current inventory records.
Practical Example
SELECT products.product_name, inventory.quantity
FROM products
LEFT JOIN inventory ON products.product_id = inventory.product_id;
Example Solution Explained:
This query outputs all products along with their inventory levels. Products without inventory data are indicated with NULL, quickly revealing stock management issues.
Example Output:
product_name | quantity
-------------|---------
Laptop | 25
Headphones | NULL
Key Takeaways:
- LEFT JOIN is perfect for comprehensive data visibility.
- Clearly identifies data completeness and inventory gaps.
What You’ll Gain from Completing This Exercise
Mastering LEFT JOIN enhances your analytical skills, making it easier to identify data gaps, ensure data integrity, and perform thorough database analyses.
Earn XP, Unlock Rewards, and Track Progress!
Log in to gain XP, unlock exciting rewards, and automatically track your progress as you enhance your SQL and analytics skills!
Schema Information
Column Name | Data Type | Description |
---|---|---|
customer_id | INTEGER | Unique identifier for each customer |
first_name | TEXT | Customer's first name |
last_name | TEXT | Customer's last name |
TEXT | Customer's email address | |
city | TEXT | City of residence |
join_date | DATE | Date the customer joined |
phone | TEXT | Customer's phone number |
Column Name | Data Type | Description |
---|---|---|
city_id | INTEGER | Unique identifier for each city |
city_name | TEXT | Name of the city |
state | TEXT | State where the city is located |
Column Name | Data Type | Description |
---|---|---|
order_id | INTEGER | Unique identifier for each order |
customer_id | INTEGER | ID of the customer who placed the order |
employee_id | INTEGER | ID of the employee who handled the order |
order_date | DATE | Date when the order was placed |
status | TEXT | Order status (e.g., Shipped, Cancelled, Pending) |
total_amount | REAL | Total amount for the order |
Column Name | Data Type | Description |
---|---|---|
order_id | INTEGER | Associated order identifier |
product_id | INTEGER | Identifier for the product |
quantity | INTEGER | Quantity of the product in the order |
unit_price | REAL | Price per unit of the product |
Column Name | Data Type | Description |
---|---|---|
product_id | INTEGER | Unique identifier for each product |
product_name | TEXT | Name of the product |
category_id | INTEGER | Category to which the product belongs |
unit_price | REAL | Price per unit of the product |
stock_quantity | INTEGER | Quantity of items available in stock |
creation_date | DATE | Date the product was added to the system |
Column Name | Data Type | Description |
---|---|---|
supplier_id | INTEGER | Unique identifier for each supplier |
supplier_name | TEXT | Name of the supplier |
city | TEXT | City where the supplier is located |
products_supplied | TEXT | List of product IDs supplied (e.g., [90,91,33,121]) |
Column Name | Data Type | Description |
---|---|---|
movement_id | INTEGER | Unique identifier for each movement record |
product_id | INTEGER | Product being moved |
change_quantity | INTEGER | Change in quantity (+/-) |
movement_date | DATE | Date of the inventory movement |
reason | TEXT | Explanation (Sale, Restock, Adjustment, etc.) |
Column Name | Data Type | Description |
---|---|---|
employee_id | INTEGER | Unique identifier for each employee |
first_name | TEXT | Employee's first name |
last_name | TEXT | Employee's last name |
department_id | INTEGER | Identifier of the department |
hire_date | DATE | Date the employee was hired |
salary | INTEGER | Employee's salary |
Column Name | Data Type | Description |
---|---|---|
department_id | INTEGER | Unique identifier for each department |
department_name | TEXT | Name of the department |
location | TEXT | Location of the department |
Column Name | Data Type | Description |
---|---|---|
shipping_id | INTEGER | Unique identifier for each shipping record |
order_id | INTEGER | Order to which the shipping address belongs |
address | TEXT | Street address for shipping |
city | TEXT | Shipping city |
state | TEXT | Shipping state |
postal_code | INTEGER | Shipping postal/ZIP code |
Column Name | Data Type | Description |
---|---|---|
category_id | INTEGER | Unique identifier for each category |
category_name | TEXT | Name of the category |