• Look at my previous post for an explanation: it's a matter of order of execution.

    Basically, what happens (from a logical point), is this:

    1. A cartesian product of the two tables is produced (the query optimizer will probably use some other algorithm in practice, but you can ignore that to understand HOW the rows are included/excluded/calculated).

    2. Each pair of rows is evaluated by the ON clause. So, the ON eliminates unneeded rows from the join.

    3. The OUTER kicks in and gets all the rows that where excluded by the ON (from one table or both).

    4. The WHERE excludes rows from the new list.

    In case of INNER joins, step 3 is not executed, so conditionals can be switched from the ON clause to the WHERE freely.

    No magic, no secrets. Only execution order.