You stated interest in "internals", and then asked an example that illustrates "semantics". I'm answering semantics.
Consider these tables.
Table1 : 1, 4, 6
Table2 : 2, 4, 5
Table3 : 3, 5, 6
Both examples perform the same join first, so I'll perform that here.
FirstResult = T1 FULL JOIN T2 : (T1, T2)
(1, null)
(4, 4)
(6, null)
(null, 2)
(null, 5)
Example (A)
FirstResult FULL JOIN T3 ON FirstItem : (T1, T2, T3)
(1, null, null)
(4, 4, null)
(6, null, 6) <----
(null, 2, null)
(null, 5, null) <----
(null, null, 3)
Example (B)
FirstResult FULL JOIN T3 ON SecondItem : (T1, T2, T3)
(1, null, null)
(4, 4, null)
(6, null, null) <----
(null, 2, null)
(null, 5, 5) <----
(null, null, 3)
This shows you logically how to produce the results from the joins.
For "internals", there's something called a query optimizer, which will produce these same results - but it will make implementation choices to do the computation/io fast. These choices include:
- which tables to access first
- look into a table using an index or table scan
- which join implementation type to use (nested loop, merge, hash).
Also note: due to the optimizer making these choices, and changing these choices based on what it considers to be optimal - the order of the results can change. The default ordering of results is always "what is easiest". If you don't want the default ordering, you need to specify ordering in your query.
To see exactly what the optimizer will do with a query (at that moment, because it can change its mind), you need to view the execution plan.