A join combines rows from two tables based on a related column. INNER JOIN returns only the rows that match in both tables.
Sample schema
CREATE TABLE departments (
code VARCHAR(10) PRIMARY KEY,
name_en VARCHAR(100) NOT NULL,
name_bn VARCHAR(100)
);
CREATE TABLE enrollments (
id INT AUTO_INCREMENT PRIMARY KEY,
student_id INT NOT NULL,
course_id INT NOT NULL,
grade CHAR(2),
FOREIGN KEY (student_id) REFERENCES students(id)
);
Basic INNER JOIN
SELECT s.name_en, d.name_en AS department
FROM students s
INNER JOIN departments d ON s.department = d.code;
INNER is optional — JOIN alone means INNER JOIN. Table aliases (s, d) keep long queries readable and are required when both tables share a column name.
USING
When the joining columns have the same name, USING is shorter and de-duplicates the column in the output:
SELECT student_id, name_en, grade
FROM students JOIN enrollments USING (student_id);
Joining three or more tables
SELECT
s.name_en AS student,
c.title AS course,
e.grade,
d.name_en AS department
FROM enrollments e
JOIN students s ON e.student_id = s.id
JOIN courses c ON e.course_id = c.id
JOIN departments d ON s.department = d.code
WHERE e.grade IS NOT NULL
ORDER BY s.name_en;
Each JOIN narrows the result: a student with no enrollment never appears.
Joins with aggregation
SELECT d.name_en AS department,
COUNT(s.id) AS students,
ROUND(AVG(s.cgpa), 2) AS avg_cgpa
FROM departments d
JOIN students s ON s.department = d.code
GROUP BY d.code, d.name_en
ORDER BY students DESC;
Non-equi joins
The ON condition does not have to be equality:
SELECT s.name_en, g.letter
FROM students s
JOIN grade_bands g ON s.cgpa BETWEEN g.min_cgpa AND g.max_cgpa;
Performance rules
- Index every column used in
ON— this is the single biggest join optimisation. - Foreign key columns should have the same type and collation as the referenced column, or MySQL cannot use the index.
- Filter with
WHEREto shrink the row sets before they are joined. - Read the plan with
EXPLAINand look fortype: ALL, which means a full table scan.