The Day SQL Joins Finally Felt Like Real Engineering

I am a full-stack developer (currently working with cognizant) who is passionate about web development and creating digital products with innovative solutions.
I hold 6+ years of experience in development, understanding clients' unique needs, and delivering quality code. I've honed my coding skills over these years through both my professional exposure and self-study. Have worked with teams that have used agile development methodology.
I am someone who likes to keep acquiring new skills and capabilities. And when I am not a web developer, I enjoy reading, writing and running.
My interests include:
- Exploring new ideas
- Learning about future tech & products
- Finding user-friendly solutions to tech-related problems
- Sharing my knowledge with close acquaintances
At some point every developer hits this moment.
You’ve learned SQL basics.
You know SELECT, INSERT, maybe even GROUP BY.
But then the product team asks something like:
“Show me the average rating for every series and who reviewed them.”
Suddenly your neat single-table queries fall apart.
Because real applications don’t store everything in one table.
Users live in one table.
Content lives in another.
Actions connecting them live somewhere else.
That’s when relational databases reveal their real power.
Not through tables.
Through relationships between tables.
In this guide, we’re going to explore multi-table relationships and advanced joins using a real-world system:
A TV Series Review Platform (think IMDb or Rotten Tomatoes).
We’ll cover:
How relational systems structure data
Bridge tables and many-to-many relationships
Practical join queries used in real APIs
Analytics queries with aggregations
Debugging missing relationships
Production insights engineers learn the hard way
Once you understand joins like this, SQL stops feeling like syntax and starts feeling like system modeling.
1️⃣ Why Real Systems Use Multiple Tables
New developers often try to store everything in one table.
Something like:
| series | reviewer | rating |
|---|---|---|
| Breaking Bad | Thomas | 9.5 |
| Breaking Bad | Wyatt | 9.3 |
Looks simple.
But it creates problems:
duplicated show data
difficult updates
inconsistent records
So real systems normalize data.
Instead of one table, we split the system into entities:
Series
Reviewers
Reviews
Each entity represents a real-world concept.
Relationships connect them.
2️⃣ The Database Structure
Our example review platform has three tables.
📺 Series Table
Stores TV show data.
CREATE TABLE series (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(100),
released_year YEAR,
genre VARCHAR(100)
);
Example:
| id | title | genre |
|---|---|---|
| 1 | Archer | Animation |
| 2 | Breaking Bad | Drama |
One series can receive many reviews.
👤 Reviewers Table
Stores users who leave ratings.
CREATE TABLE reviewers (
id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50),
last_name VARCHAR(50)
);
Example:
| id | name |
|---|---|
| 1 | Thomas |
| 2 | Wyatt |
Each reviewer can write many reviews.
⭐ Reviews Table (The Bridge)
This table connects reviewers and shows.
CREATE TABLE reviews (
id INT PRIMARY KEY AUTO_INCREMENT,
rating DECIMAL(2,1),
series_id INT,
reviewer_id INT,
FOREIGN KEY(series_id) REFERENCES series(id),
FOREIGN KEY(reviewer_id) REFERENCES reviewers(id)
);
Relationship structure:
reviewers
|
| (1:M)
|
reviews
|
| (M:1)
|
series
Meaning:
1 reviewer → many reviews
1 series → many reviews
The reviews table acts as a bridge between the other two tables.
3️⃣ Your First Real Join Query
Let’s answer a simple question.
Show each series with its ratings.
SELECT
title, rating
FROM series
JOIN reviews
ON series.id = reviews.series_id;
Example result:
| title | rating |
|---|---|
| Archer | 8.0 |
| Archer | 7.5 |
Each row represents:
One review for one series
This is what joins do:
They combine related rows from different tables.
4️⃣ Calculating Average Rating per Series
Every streaming platform shows average ratings.
We can compute them using joins + aggregation.
SELECT
title,
ROUND(AVG(rating), 2) AS avg_rating
FROM series
JOIN reviews
ON series.id = reviews.series_id
GROUP BY title
ORDER BY avg_rating;
Example:
| title | avg_rating |
|---|---|
| Breaking Bad | 9.36 |
| Fargo | 9.40 |
This powers features like:
ranking pages
trending shows
recommendation algorithms
5️⃣ Finding Series With No Reviews
Product managers ask this all the time:
“Which shows haven’t received reviews yet?”
Use a LEFT JOIN.
SELECT
title AS unreviewed_series
FROM series
LEFT JOIN reviews
ON series.id = reviews.series_id
WHERE rating IS NULL;
Explanation:
LEFT JOIN keeps all series rows.
If no review exists:
rating = NULL
Which makes those series easy to find.
Alternative Using RIGHT JOIN
SELECT
title AS unreviewed_series
FROM reviews
RIGHT JOIN series
ON series.id = reviews.series_id
WHERE rating IS NULL;
Both queries return the same result.
But most engineers prefer LEFT JOIN for readability.
6️⃣ Genre Analytics
Streaming companies constantly analyze content performance.
Example question:
Which genres receive the highest ratings?
SELECT
genre,
ROUND(AVG(rating), 2) AS avg_rating
FROM series
JOIN reviews
ON series.id = reviews.series_id
GROUP BY genre;
Example output:
| genre | avg_rating |
|---|---|
| Drama | 8.75 |
| Comedy | 7.90 |
These insights drive decisions like:
which genres to invest in
which shows to promote
7️⃣ Reviewer Activity Analytics
Platforms also analyze user engagement.
Example query:
SELECT
first_name,
last_name,
COUNT(rating) AS count,
IFNULL(MIN(rating),0) AS min,
IFNULL(MAX(rating),0) AS max,
ROUND(IFNULL(AVG(rating),0),2) AS average,
CASE
WHEN COUNT(rating) >= 10 THEN 'POWERUSER'
WHEN COUNT(rating) > 0 THEN 'ACTIVE'
ELSE 'INACTIVE'
END AS status
FROM reviewers
LEFT JOIN reviews
ON reviewers.id = reviews.reviewer_id
GROUP BY first_name, last_name;
Example result:
| reviewer | count | status |
|---|---|---|
| Thomas | 12 | POWERUSER |
| Pinkie | 4 | ACTIVE |
| Marlon | 0 | INACTIVE |
Real systems use this logic to:
reward top contributors
detect inactive users
drive gamification features
8️⃣ Joining Three Tables Together
Now let’s combine everything.
Question:
Who reviewed which series?
SELECT
title,
rating,
CONCAT(first_name,' ',last_name) AS reviewer
FROM reviews
INNER JOIN series
ON reviews.series_id = series.id
INNER JOIN reviewers
ON reviews.reviewer_id = reviewers.id;
Result:
| title | rating | reviewer |
|---|---|---|
| Archer | 8.0 | Thomas Stoneman |
| Archer | 7.5 | Wyatt Skaggs |
Three tables.
One query.
That’s relational power.
9️⃣ Join Order Flexibility
Interestingly, join order usually doesn’t matter.
All of these work:
series → reviews → reviewers
reviews → series → reviewers
reviewers → reviews → series
Why?
Because joins depend on foreign key relationships, not the order written.
The query optimizer decides execution order internally.
🛠 DevOps & Production Perspective
In production systems, join queries power:
recommendation engines
reporting dashboards
analytics pipelines
user activity tracking
But joins can also cause problems:
missing indexes → slow queries
huge tables → heavy CPU usage
expensive aggregations
Large platforms often:
index foreign keys
cache aggregated results
run analytics queries on replicas
The question engineers constantly ask is:
“Can this join scale to millions of rows?”
🧠 Mental Model to Lock In
Tables store entities.
Relationships connect entities.
Joins reconstruct the real-world relationships between data.
If CRUD stores data…
Joins explain how that data interacts.
That’s the heart of relational databases.
The Bridge Back
Remember the moment joins felt confusing?
Eventually something shifts.
You stop thinking:
“Which table has this column?”
And start thinking:
“How are these entities connected?”
That’s when SQL becomes powerful.
Because real systems aren’t about tables.
They’re about relationships.



