08 - SQL Joins
1749 words
9 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# 08 - SQL Joins ## 🎯 Learning Objectives After reading this topic, you will be able to: - Differentiate between natural join, inner join, and outer joins - Write LEFT, RIGHT, and FULL OUTER JOIN queries - Understand when each join type is appropriate - Write join conditions using ON and USING clauses ## 📋 Prerequ...

08 - SQL Joins
🎯 Learning Objectives
After reading this topic, you will be able to:
- Differentiate between natural join, inner join, and outer joins
- Write LEFT, RIGHT, and FULL OUTER JOIN queries
- Understand when each join type is appropriate
- Write join conditions using ON and USING clauses
📋 Prerequisites
- 05 - SQL Queries — SELECT-FROM-WHERE with multiple tables
- 03 - Relational Model — Foreign keys, referential integrity
📖 Core Content
8.1 Intuition: Combining Tables
In a relational database, data is spread across multiple tables to avoid redundancy. To answer meaningful questions, you need to join tables back together.
Example: An instructor teaches a course. The instructor's details are in
instructor, the teaching assignment is in teaches. To find "which instructor teaches which course", you join these tables.
The JOIN operation matches rows from two tables based on a join condition (typically a foreign key = primary key).
(Diagram)Why This Matters: Joins are the most powerful and commonly used SQL operation. Understanding join types is essential for writing correct queries.
8.2 Join Types Overview
(Diagram)
8.3 Inner Join
The inner join returns rows where the join condition matches. Rows that don't match are excluded.
sql-- Explicit inner join (using JOIN keyword) SELECT I.name, T.course_id FROM instructor I JOIN teaches T ON I.ID = T.ID; -- Equivalent: implicit join (comma + WHERE) SELECT I.name, T.course_id FROM instructor I, teaches T WHERE I.ID = T.ID;
| name | course_id |
|---|---|
| Srinivasan | CS-101 |
| Srinivasan | CS-315 |
| ... | ... |
Only matching rows appear. If an instructor teaches no courses, they don't appear. If a course has no instructor, it doesn't appear.
8.4 Natural Join
Natural join automatically joins on all columns with the same name:
sqlSELECT name, course_id FROM instructor NATURAL JOIN teaches;
This implicitly joins on
ID (the common column in both tables).
⚠️ Danger: Natural join can produce unexpected results if there are accidental common column names. For example, joining instructor and department:sqlSELECT name, building FROM instructor NATURAL JOIN department;
This joins on
dept_name (correct) — but what if both also had a name column? It would join on BOTH columns, likely producing wrong results.
Safer alternative: Use USING to specify the join columns:sqlSELECT name, building FROM instructor JOIN department USING (dept_name);
8.5 Theta Join
A theta join uses any arbitrary condition (not just equality):
sql-- Join where instructor salary > department budget (unusual, but valid) SELECT I.name, I.salary, D.budget FROM instructor I JOIN department D ON I.salary > D.budget;
The theta join is the most general join — it includes every row pair satisfying the condition.
8.6 Outer Joins
Outer joins preserve non-matching rows by padding with NULLs.
LEFT OUTER JOIN
Preserves all rows from the left table:
sqlSELECT I.name, T.course_id FROM instructor I LEFT OUTER JOIN teaches T ON I.ID = T.ID;
| name | course_id |
|---|---|
| Srinivasan | CS-101 |
| Srinivasan | CS-315 |
| Wu | FIN-201 |
| ... | ... |
| Mozart | NULL |
RIGHT OUTER JOIN
Preserves all rows from the right table:
sqlSELECT I.name, T.course_id FROM instructor I RIGHT OUTER JOIN teaches T ON I.ID = T.ID;
All courses appear, even those without an instructor.
FULL OUTER JOIN
Preserves all rows from both tables:
sqlSELECT I.name, T.course_id FROM instructor I FULL OUTER JOIN teaches T ON I.ID = T.ID;
Every instructor and every course appears. Unmatched rows show NULLs on the other side.
8.7 Visualizing Joins with Venn Diagrams
(Diagram)
| Join Type | Result Contains |
|---|---|
| INNER JOIN | Only matching rows from both tables |
| LEFT JOIN | All rows from left table + matching right rows (NULL otherwise) |
| RIGHT JOIN | All rows from right table + matching left rows (NULL otherwise) |
| FULL JOIN | All rows from both tables (NULL otherwise) |
| NATURAL JOIN | Matching rows on common columns (automatic) |
| CROSS JOIN | Cartesian product (every combination) |
8.8 Worked Examples
Example 1: Find all instructors and the courses they teach (including those who teach nothing)
sqlSELECT I.ID, I.name, T.course_id FROM instructor I LEFT OUTER JOIN teaches T ON I.ID = T.ID;
This shows ALL instructors. Those with no teaching assignment have NULL in course_id.
Example 2: Find all courses and the instructors who teach them (including courses with no instructor)
sqlSELECT C.course_id, C.title, T.ID FROM course C LEFT OUTER JOIN teaches T ON C.course_id = T.course_id;
Example 3: Full outer join — instructor and department
sqlSELECT * FROM instructor I FULL OUTER JOIN department D ON I.dept_name = D.dept_name;
Shows all instructors and all departments. An instructor in a non-existent department would have NULL department columns. A department with no instructors would have NULL instructor columns.
8.9 Join Conditions: ON vs USING vs WHERE
| Clause | Example | Notes |
|---|---|---|
| ON | JOIN ON I.ID = T.ID | Most flexible; any condition |
| USING | JOIN USING (dept_name) | Both columns must have same name |
| NATURAL | NATURAL JOIN | Automatic on all same-named columns |
| WHERE | FROM I, T WHERE I.ID = T.ID | Old-style; equivalent to INNER JOIN ON |
📐 Key Formulas / Concepts
| Join Type | Syntax | All Left Rows? | All Right Rows? |
|---|---|---|---|
| Inner Join | JOIN ... ON | No | No |
| Left Outer | LEFT JOIN ... ON | Yes | No |
| Right Outer | RIGHT JOIN ... ON | No | Yes |
| Full Outer | FULL JOIN ... ON | Yes | Yes |
| Natural | NATURAL JOIN | No | No (automatic matching) |
| Cross | CROSS JOIN | N/A | N/A (Cartesian) |
⚠️ Common Pitfalls
Pitfall 1: Natural Join Joins on ALL Common Columns
The Mistake: Using NATURAL JOIN when tables share columns unintentionally.
Why It's Wrong: If both tables have columns
dept_name AND name, NATURAL JOIN joins on BOTH, not just dept_name. This usually produces an empty result (no row has the same dept_name and same name).
Fix: Use JOIN USING (dept_name) to specify exactly which columns to join on.Pitfall 2: Confusing LEFT and RIGHT Join Direction
The Mistake: "LEFT JOIN keeps all rows from the right table."
Memory Aid: Think of LEFT JOIN as preserving the table written on the left side of
JOIN:sqlSELECT * FROM A LEFT JOIN B ON ... -- preserves A (left) SELECT * FROM A RIGHT JOIN B ON ... -- preserves B (right)
Or just use LEFT JOIN consistently and reorder the tables.
Pitfall 3: Thinking Outer Joins Are Always Better
The Mistake: Always using LEFT JOIN "to be safe."
Why It's Wrong: If you need only matching rows, INNER JOIN is:
- More explicit about your intent
- Faster (the optimizer knows it can eliminate non-matching rows early)
- The correct semantic choice Fix: Use INNER JOIN when you want only matching rows; use OUTER JOIN when you need non-matching rows preserved.
📝 Practice Questions
Q1. Write a query using LEFT JOIN to list all departments and the number of instructors in each (including departments with zero instructors).
AnswersqlSELECT D.dept_name, COUNT(I.ID) AS num_instructors FROM department D LEFT JOIN instructor I ON D.dept_name = I.dept_name GROUP BY D.dept_name;Without LEFT JOIN, departments with no instructors would be missing from the result. COUNT(I.ID) counts only non-NULL IDs, giving 0 for empty departments.
Q2. What is the difference between INNER JOIN and LEFT JOIN?
Answer
- INNER JOIN: Returns only rows where the join condition matches in both tables. Non-matching rows are excluded.
- LEFT JOIN: Returns ALL rows from the left table, with matching data from the right table. Non-matching rows have NULL for right-table columns.
Use INNER JOIN when you need only related data; use LEFT JOIN when you need ALL data from the primary table regardless of matches.
Q3. Write a NATURAL JOIN query and its equivalent using JOIN...ON.
Answersql-- Natural join SELECT name, course_id FROM instructor NATURAL JOIN teaches; -- Equivalent with ON clause SELECT I.name, T.course_id FROM instructor I JOIN teaches T ON I.ID = T.ID;NATURAL JOIN automatically finds common column names and joins on them.
Q4. When would you use a FULL OUTER JOIN?
AnswerUse FULL OUTER JOIN when you need ALL rows from both tables, regardless of whether they match. Example:
- Show all employees and all departments: every employee appears (even those in no department), and every department appears (even those with no employees).
FULL OUTER JOIN = LEFT JOIN ∪ RIGHT JOIN (with duplicate removal).
Q5. Write a RIGHT JOIN that is equivalent to a given LEFT JOIN.
Answersql-- LEFT JOIN: preserves instructors SELECT I.name, T.course_id FROM instructor I LEFT JOIN teaches T ON I.ID = T.ID; -- Equivalent RIGHT JOIN: move tables SELECT I.name, T.course_id FROM teaches T RIGHT JOIN instructor I ON T.ID = I.ID;RIGHT JOIN is the mirror image — just swap the table order.
Q6. What is a theta join? Give an example.
AnswerA theta join joins tables using any arbitrary condition (not just equality). The condition can use any comparison operator: =, <, >, <=, >=, <>.Example: Find instructor-department pairs where the instructor's salary exceeds the department's budget:sqlSELECT I.name, D.dept_name, I.salary, D.budget FROM instructor I JOIN department D ON I.salary > D.budget;
Q7. Why is NATURAL JOIN considered unsafe?
AnswerNATURAL JOIN automatically joins on ALL columns with the same name. If:
- You later add a column to one table with the same name as a column in the other table
- Two tables accidentally share a column name with different semantics
The join condition changes silently, potentially producing wrong results without errors.Example: Ifinstructorandstudentboth have anamecolumn,NATURAL JOINwould join on bothdept_nameANDname, which is almost certainly wrong.
Q8. Write a query to find instructors who do NOT teach any course, using an outer join.
AnswersqlSELECT I.ID, I.name FROM instructor I LEFT JOIN teaches T ON I.ID = T.ID WHERE T.ID IS NULL;The LEFT JOIN keeps all instructors. Those who don't teach have NULL in T.ID. Filtering withWHERE T.ID IS NULLfinds only those non-teaching instructors.
🔗 Cross-References
- Next Topic: 09 - SQL Functions, Procedures & Triggers
- Previous Topic: 07 - Advanced SQL
- Related: BSCS2003 (MAD 1) — JOIN queries in web app backends
- Related: 10 - Relational Algebra — Join in relational algebra (⋈)
- Textbook: Silberschatz, Korth, Sudarshan — Chapter 4 (Intermediate SQL) Join Discord Previous07 - Advanced SQLNext09 - SQL Functions & Triggers