Free tutorials & notes in Hindi & English · Clean code examples · Mobile friendly learning
MySQL + SQL · Lesson 1

Join Three Tables

Think in a Relationship Path

A three-table query is not a magical new syntax. It is a sequence of relationships. Students connect to results through student_id; results connect to subjects through subject_code. Students do not need a direct subject column.

Path: join_students → results → subjects. Verify the key and cardinality at each arrow before writing SELECT columns.

Extend the School Lab

CREATE TABLE subjects (
  subject_code VARCHAR(10) PRIMARY KEY,
  subject_name VARCHAR(60) NOT NULL
);

CREATE TABLE results (
  student_id INT NOT NULL,
  subject_code VARCHAR(10) NOT NULL,
  marks DECIMAL(5,2) NOT NULL,
  PRIMARY KEY (student_id, subject_code),
  FOREIGN KEY (student_id)
    REFERENCES join_students(student_id),
  FOREIGN KEY (subject_code)
    REFERENCES subjects(subject_code)
);

INSERT INTO subjects VALUES
('CSC', 'Computer Science'),
('MAT', 'Mathematics');

INSERT INTO results VALUES
(1, 'MAT', 86), (1, 'CSC', 91),
(2, 'MAT', 92), (3, 'CSC', 74),
(4, 'MAT', 89);

The composite primary key prevents two result rows for the same student and subject. One student can still have many subjects.

Verified Three-Table JOIN

SELECT s.student_name,
       sub.subject_name,
       r.marks
FROM join_students AS s
JOIN results AS r
  ON r.student_id = s.student_id
JOIN subjects AS sub
  ON sub.subject_code = r.subject_code
ORDER BY s.student_id, sub.subject_code;
Aarav | Computer Science | 91.00 Aarav | Mathematics | 86.00 Meera | Mathematics | 92.00 Kabir | Computer Science | 74.00 Sana | Mathematics | 89.00

Five result records produce five rows. Aarav legitimately appears twice because Aarav has two subjects. Vihaan disappears because there is no result match.

Read and Build the Join Path

  1. Start with the population required by the report.
  2. Join the bridge or transaction table using its foreign key.
  3. Join the descriptive master table using the next foreign key.
  4. Qualify common columns and choose only needed output fields.
  5. Predict how every one-to-many edge changes row count.
Do not join students directly to subjects with an unrelated column or CROSS JOIN and then filter later. The results table is the fact that proves a student took a subject.

Aggregate the Joined Grain Safely

SELECT s.student_id, s.student_name,
       COUNT(r.subject_code) AS subjects_taken,
       ROUND(AVG(r.marks), 2) AS average_marks
FROM join_students AS s
JOIN results AS r
  ON r.student_id = s.student_id
GROUP BY s.student_id, s.student_name
ORDER BY s.student_id;
1 | Aarav | 2 | 88.50 2 | Meera | 1 | 92.00 3 | Kabir | 1 | 74.00 4 | Sana | 1 | 89.00

Define the report grain: one row per student. Adding another one-to-many table, such as attendance details, could multiply result rows and corrupt AVG or SUM. Aggregate each fact separately before joining when grains differ.

Preserve Students with No Results

SELECT s.student_name,
       COUNT(r.subject_code) AS subjects_taken,
       ROUND(AVG(r.marks), 2) AS average_marks
FROM join_students AS s
LEFT JOIN results AS r
  ON r.student_id = s.student_id
GROUP BY s.student_id, s.student_name
ORDER BY s.student_id;
Aarav | 2 | 88.50 Meera | 1 | 92.00 Kabir | 1 | 74.00 Sana | 1 | 89.00 Vihaan | 0 | NULL

COUNT of the result key returns zero for Vihaan; AVG has no non-NULL input and returns NULL. If subject names are needed too, LEFT JOIN subjects from r.subject_code so the optional chain remains optional.

Debug and Optimize

  • Add one JOIN at a time and count rows after each step.
  • Select both sides of each key temporarily.
  • Check composite keys and unique constraints.
  • Place optional-side filters in ON when the starting population must survive.
  • Index foreign keys: results.student_id and results.subject_code are covered by the composite primary key only in its leftmost order; an additional subject_code index may help subject-driven access.
  • Use EXPLAIN after correctness tests.

Practice: add class_name as a fourth table; calculate class averages without double-counting; list every student and only Mathematics marks while preserving students with no Mathematics result.

Official References

Syntax and optimizer notes were checked against the official MySQL 8.4 manual. Always test plans and row counts on your own schema and data.

Frequently Asked Questions

How do I join three tables in MySQL?
Start from the required population, add each table with an explicit JOIN and ON relationship, and use aliases. Every new table must connect through a valid path.
Does written JOIN order control execution order?
It expresses the logical query, but MySQL may choose a different physical order for inner joins. Outer-join dependencies restrict some reorderings.
Why does adding a third table multiply rows?
The third table may have multiple matches for each existing result row. Confirm each edge's one-to-one, one-to-many or many-to-many cardinality.
How do I keep students with no results?
Start from students and LEFT JOIN results, then LEFT JOIN subjects through the nullable result row. Avoid NULL-rejecting WHERE predicates on those optional tables.
Where should I filter one optional subject?
Put the subject restriction in the relevant ON clause if all students must remain. Use WHERE if the final report should include only matched subject rows.
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

💻 Live Code Editor

This page's programs are ready here — run them, edit them, and learn. No installation needed.
Powered by OneCompiler. The code loads into the editor automatically — press Run to see the output. If the editor does not open, open it in a new tab.