Why LEFT JOIN Still Returns All Left Rows: ON vs WHERE Explained
This article explains why a LEFT JOIN always returns all rows from the left table, clarifies the difference between ON and WHERE clauses, demonstrates the behavior with multiple SQL examples and code snippets, and highlights the special handling of LEFT/RIGHT/FULL joins versus inner joins.
When writing SQL, I tried to use
A LEFT JOIN B ON ... AND ...to merge two rows into one, but still got two rows.
I later discovered that the
ANDafter
ONdoes not filter the result count; it only determines whether rows from table B are shown, while rows from table A are always returned.
Regardless of whether the condition after
ANDis
A.id = 1or
B.id = 1, all records from table A appear, with matching B records (or nulls) for the specified condition.
Example SQL:
<code>SELECT *
FROM student s
LEFT JOIN class c ON s.classId = c.id
ORDER BY s.id</code>Adding an
ANDcondition to the
ONclause:
<code>SELECT *
FROM student s
LEFT JOIN class c ON s.classId = c.id AND s.name = '张三'
ORDER BY s.id</code>Using
ONversus
WHEREin a LEFT JOIN:
The ON condition is applied while generating the temporary table; it does not remove rows from the left table, even if the condition is false.
The WHERE condition filters the temporary table after it is created, so rows that do not satisfy the condition are removed entirely.
Assume two tables:
Table 1:
Table 2:
Two SQL queries:
<code>SELECT * FROM tab1 LEFT JOIN tab2 ON (tab1.size = tab2.size) WHERE tab2.name='AAA'</code> <code>SELECT * FROM tab1 LEFT JOIN tab2 ON (tab1.size = tab2.size AND tab2.name='AAA')</code>Process of the first query:
Intermediate table uses
ONcondition:
tab1.size = tab2.size.
After the temporary table is created, the
WHEREclause filters rows where
tab2.name='AAA'.
Process of the second query:
Intermediate table uses combined
ONcondition:
tab1.size = tab2.size AND tab2.name='AAA'.
Note: Even if the condition is false, LEFT JOIN still returns rows from the left table.
The special nature of
LEFT JOIN,
RIGHT JOIN, and
FULL JOINis that they always return rows from the respective side(s) regardless of the
ONcondition, whereas
INNER JOINdoes not have this behavior; placing the condition in
ONor
WHEREyields the same result set.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.