ON specifies how rows are matched.
WHERE filters the result after the join logically occurs.
Example:
SELECT *
FROM customers c
LEFT JOIN orders o
ON c.id = o.customer_id
WHERE o.amount > 100;That WHERE can drop customers who have no matching orders (the LEFT JOIN starts acting like an INNER JOIN).
Compare:
SELECT *
FROM customers c
LEFT JOIN orders o
ON c.id = o.customer_id
AND o.amount > 100;Now customers without qualifying orders can still appear.
Gotcha:
Moving conditions between ON and WHERE is not always the same, especially with LEFT, RIGHT, or FULL OUTER JOIN.