SQL JOINs are one of the most powerful features in database querying, allowing you to combine data from multiple tables. If you’re new to SQL or struggling to understand how different types of JOINs work, this comprehensive guide with visual diagrams will help you master them.
💡 New to database relationships? Before diving into JOINs, make sure you understand how tables relate to each other. Check out our comprehensive guide to database relationships to learn the fundamentals of one-to-one, one-to-many, and many-to-many relationships.
Sample Data Setup
Throughout this tutorial, we’ll use two simple tables: employees
and departments
. This realistic scenario will help you understand how JOINs work in practice.
employees
table:
emp_id | name | dept_id |
---|---|---|
1 | Alice | 10 |
2 | Bob | 20 |
3 | Charlie | 10 |
4 | Diana | NULL |
departments
table:
dept_id | dept_name |
---|---|
10 | Engineering |
20 | Marketing |
30 | Sales |
Let’s create these tables:
-- Create employees table
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
name VARCHAR(50),
dept_id INT
);
-- Insert sample data
INSERT INTO employees VALUES
(1, 'Alice', 10),
(2, 'Bob', 20),
(3, 'Charlie', 10),
(4, 'Diana', NULL);
-- Create departments table
CREATE TABLE departments (
dept_id INT PRIMARY KEY,
dept_name VARCHAR(50)
);
-- Insert sample data
INSERT INTO departments VALUES
(10, 'Engineering'),
(20, 'Marketing'),
(30, 'Sales');
Now let’s explore each type of JOIN with diagrams and examples.
INNER JOIN
An INNER JOIN returns only the rows that have matching values in both tables.
Example:
SELECT e.name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
Result:
name | dept_name |
---|---|
Alice | Engineering |
Bob | Marketing |
Charlie | Engineering |
Explanation: Only employees with valid department IDs are returned. Diana (with NULL dept_id) and the Sales department (with no employees) are excluded.
LEFT JOIN (LEFT OUTER JOIN)
A LEFT JOIN returns all rows from the left table and matching rows from the right table. If no match exists, NULL values are returned for the right table columns.
Example:
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;
Result:
name | dept_name |
---|---|
Alice | Engineering |
Bob | Marketing |
Charlie | Engineering |
Diana | NULL |
Explanation: All employees are returned. Diana appears with a NULL department name because her dept_id is NULL.
RIGHT JOIN (RIGHT OUTER JOIN)
A RIGHT JOIN returns all rows from the right table and matching rows from the left table. If no match exists, NULL values are returned for the left table columns.
Example:
SELECT e.name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.dept_id;
Result:
name | dept_name |
---|---|
Alice | Engineering |
Charlie | Engineering |
Bob | Marketing |
NULL | Sales |
Explanation: All departments are returned. The Sales department appears with a NULL employee name because no employees belong to it.
FULL OUTER JOIN
A FULL OUTER JOIN returns all rows from both tables. When there’s no match, NULL values are returned for the missing side.
Example:
SELECT e.name, d.dept_name
FROM employees e
FULL OUTER JOIN departments d ON e.dept_id = d.dept_id;
Result:
name | dept_name |
---|---|
Alice | Engineering |
Bob | Marketing |
Charlie | Engineering |
Diana | NULL |
NULL | Sales |
Explanation: All employees and all departments are returned. Diana has no department, and Sales has no employees.
Note: MySQL doesn’t support FULL OUTER JOIN directly. See our MySQL FULL OUTER JOIN workaround guide for alternatives.
CROSS JOIN
A CROSS JOIN returns the Cartesian product of both tables - every row from the first table combined with every row from the second table.
Example:
SELECT e.name, d.dept_name
FROM employees e
CROSS JOIN departments d;
Result (first 6 rows):
name | dept_name |
---|---|
Alice | Engineering |
Alice | Marketing |
Alice | Sales |
Bob | Engineering |
Bob | Marketing |
Bob | Sales |
… (continues for all combinations) |
Explanation: Each employee is paired with each department, resulting in 4 × 3 = 12 total rows.
Warning: CROSS JOINs can produce very large result sets. Use with caution!
LEFT ANTI JOIN (Left Excluding Join)
A LEFT ANTI JOIN returns rows from the left table that have no matching rows in the right table.
Example:
SELECT e.name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id
WHERE d.dept_id IS NULL;
Result:
name |
---|
Diana |
Explanation: Only Diana is returned because she’s the only employee without a valid department.
RIGHT ANTI JOIN (Right Excluding Join)
A RIGHT ANTI JOIN returns rows from the right table that have no matching rows in the left table.
Example:
SELECT d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.dept_id
WHERE e.dept_id IS NULL;
Result:
dept_name |
---|
Sales |
Explanation: Only Sales is returned because it’s the only department with no employees.
When to Use Each JOIN Type
- INNER JOIN: When you only want records that exist in both tables
- LEFT JOIN: When you want all records from the main table, even if some don’t have matches
- RIGHT JOIN: When you want all records from the secondary table (less common than LEFT JOIN)
- FULL OUTER JOIN: When you want to see everything from both tables, regardless of matches
- CROSS JOIN: When you need all possible combinations (use sparingly)
- ANTI JOINs: When you want to find records that don’t have matches
JOINs and Database Relationships
Different JOIN types work best with specific database relationship patterns:
One-to-One Relationships
- Use LEFT JOIN to include parent records even without related data
- Example: Users and their profiles (not all users have profiles)
SELECT u.username, p.bio FROM users u LEFT JOIN user_profiles p ON u.id = p.user_id;
One-to-Many Relationships
- Use INNER JOIN when you need both parent and child data
-
Use LEFT JOIN when you want all parents, even those without children
```sql
– All customers with their orders (excludes customers with no orders)
SELECT c.name, o.total
FROM customers c
INNER JOIN orders o ON c.id = o.customer_id;
– All customers, showing order count (includes customers with 0 orders)
SELECT c.name, COUNT(o.id) as order_count
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.id, c.name;
**👉 [Learn more about one-to-many relationships](/blog/one-to-many-database-relationships-complete-guide)**
### Many-to-Many Relationships
- **Requires joining through junction tables** with multiple JOINs
- Often uses INNER JOINs to connect through the bridge table
```sql
-- Students with their enrolled courses (through enrollments junction table)
SELECT s.name, c.course_name, e.grade
FROM students s
INNER JOIN enrollments e ON s.id = e.student_id
INNER JOIN courses c ON e.course_id = c.id;
👉 Learn more about many-to-many relationships
Performance Tips
- Use indexes on JOIN columns for better performance
- Filter early using WHERE clauses to reduce the dataset
- Be careful with CROSS JOINs - they can create massive result sets
- Consider the order of tables in complex JOINs
Practice with Beekeeper Studio
The best way to master SQL JOINs is through practice. Try these examples and experiment with your own data using Beekeeper Studio, a modern SQL editor that makes it easy to visualize your query results and understand how JOINs work.
Conclusion
SQL JOINs are essential for working with relational databases. By understanding these visual patterns and practicing with real data, you’ll be able to combine tables effectively and extract meaningful insights from your databases.
Remember:
- Start with INNER JOINs for basic relationships
- Use LEFT JOINs when you need to preserve all records from your main table
- Be mindful of NULL values in your data
- Always test your JOINs with sample data first
Continue Learning
Now that you understand SQL JOINs, dive deeper into the database design concepts that make JOINs possible:
- Understanding Database Relationships: Complete Beginner’s Guide - Learn how to design relationships between tables
- One-to-One Relationships: Complete Guide - Master 1:1 relationships with detailed examples
- One-to-Many Relationships: Complete Guide - The most common relationship pattern explained
- Many-to-Many Relationships: Complete Guide - Complex relationships with junction tables
Happy querying!
Beekeeper Studio Is A Free & Open Source Database GUI
Best SQL query & editor tool I have ever used. It provides everything I need to manage my database. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio is fast, intuitive, and easy to use. Beekeeper supports loads of databases, and works great on Windows, Mac and Linux.
What Users Say About Beekeeper Studio
"Beekeeper Studio completely replaced my old SQL workflow. It's fast, intuitive, and makes database work enjoyable again."
"I've tried many database GUIs, but Beekeeper strikes the perfect balance between features and simplicity. It just works."