SQL: INNER JOIN Filters Belong in the Right Place
Put table relationship predicates in ON and row filters in WHERE. The query is easier to inspect and harder to break.
The symptom
An inner join query technically works, but the join condition is buried in
WHERE with ordinary filters. It usually looks like the older
comma join below, since a JOIN with no ON at all
is a syntax error in DuckDB and PostgreSQL. When the result looks wrong, it
is harder to tell whether the bug is the table relationship or the row
filter.
select c.customer_id, o.order_id
from customers as c, orders as o
where o.customer_id = c.customer_id
and o.status = 'shipped' Why it happens
For INNER JOINs, a key match in WHERE can produce the same rows
as the same key match in ON. That does not make it a good
habit. Relationship logic and row-filter logic answer different questions,
and mixing them makes missing or incomplete join predicates easier to miss.
The fix
Put the relationship in ON. Put filters about which rows you
want in WHERE. The result is clearer, and the same habit
prevents serious bugs when the query later changes to a LEFT JOIN.
select c.customer_id, o.order_id
from customers as c
join orders as o on o.customer_id = c.customer_id
where o.status = 'shipped'
With LEFT JOINs, moving right-table filters between ON and
WHERE can change the result. Keeping the habit clear for INNER
JOINs makes that difference easier to reason about later.
Learn more
Related
Join two related tables on a key.
INNER, LEFT, RIGHT, FULL, and CROSS joins.
Join types and common join patterns.
Practice join keys, left joins, duplicate rows, and debugging.
Qualify shared columns with a table alias.
Join through a bridge table.