Difference between ON and WHERE clauses in SQL table joins - sql

select e.last_name, e.hire_date
from employees e join employees m
on (m.last_name = 'Davies')
and (e.hire_date > m.hire_date);
select e.last_name, e.hire_date
from employees e join employees m
on (m.last_name = 'Davies')
where (e.hire_date > m.hire_date);
select e.last_name, e.hire_date
from employees e join employees m
on (e.hire_date > m.hire_date)
where (m.last_name = 'Davies');
These three statements have the same result. Apart from the fact that where cannot be used exclusively, without using on, is there any particular reason to use where at all in table joins?

The main difference is when you are using different joins.
Typically you should see the same result if you were to use inner joins, but once you start using LEFT joins the results will change.
Have a look at the following example
SQL Fiddle DEMO
And have a look at the following article (very explanatory)
EDIT for #ShannonSeverance
Schema and Test data
CREATE TABLE Table1 (
ID INT,
Val VARCHAR(20)
);
INSERT INTO Table1 VALUES (1,'a');
INSERT INTO Table1 VALUES (2,'a');
CREATE TABLE Table2 (
ID INT,
Val VARCHAR(20)
);
INSERT INTO Table2 VALUES (1,'a');
and Tests
SELECT t1.ID,
t1.Val,
t2.ID ID2,
t2.Val Val2
FROM Table1 t1 INNER JOIN
Table2 t2 ON t1.ID = t2.ID AND t1.Val = t2.Val;
SELECT t1.ID,
t1.Val,
t2.ID ID2,
t2.Val Val2
FROM Table1 t1,Table2 t2
WHERE t1.ID = t2.ID
AND t1.Val = t2.Val;
SELECT t1.ID,
t1.Val,
t2.ID ID2,
t2.Val Val2
FROM Table1 t1 LEFT JOIN
Table2 t2 ON t1.ID = t2.ID AND t1.Val = t2.Val;
SELECT t1.ID,
t1.Val,
t2.ID ID2,
t2.Val Val2
FROM Table1 t1 LEFT JOIN
Table2 t2 ON t1.ID = t2.ID
WHERE t1.Val = t2.Val;

where is a filter which is applied after rows are selected using the join. It is not always the case that a join ... on condition is sematically equivalent to a where condition. Therefore, yes, there is a particular reason to use a where in table joins: when it does the right thing.
...and by contrast, the ON condition executes as the join is being made. ON conditions for joins earlier in multi-table joins can cut off millions of unnecessary joins so are generally preferred if semantically correct
– Bohemian

Using on usually used for querying more than one table. When making that query, tables must have relationship each other, in general the same value in a specific fields.
on will connect that same value, for example:
**table1**:
id_name id_position name
1 1 john
2 2 doe
3 2 tom
4 3 hawkins
**table2**
id_position position
1 system analyst
2 programmer
SELECT t1.id_name, t1.name, t2.position
FROM table1 t1 LEFT JOIN table2 t2
ON t1.id_position = t2.id_position
-- RESULT:
id_name name position
1 john system analyst
2 doe programmer
3 tom programmer
4 hawkins NULL -- NO MATCH IN table 2
as we can see on will connect table1 and table2 that have same value id_position, so it is a little different from what you have been written above.
While where can be used in every query and not depends how many tables in that query. In general where is used for conditional thing that we want.

The difference lies in when the engine performs the filtering. A "where" represents a filter on the computed product of both tables. The "on" keyword specifies how a join is performed. They are not semantically equivalent even if sometimes they both produce the same outcome.
Cheers

The ON clause defines the relationship between the tables.
ON Clause supports all join types.
The WHERE clause describes which rows you are interested in.
WHERE Clause only supports for Inner join not for Outer joins like LEFT
JOIN and RIGHT JOIN.

Related

Combine two tables on same columns

I have 2 tables as showen below:
TABLE 1: Name Age Weight(Kilo)
Tom 16 56
Alex 29 89
TABLE 2: Name Age Sex
Tom 16 M
Alex 29 M
What I want to get:
TABLE 3: Name Age Sex Weight(Kilo)
Tom 16 M 56
Alex 29 M 89
I have tried Union/Union All and it doesn't work. Also tried to use Join but it gives me a table with duplicate values. Any idea how to do this?
Assuming your Name/Age values match up exactly between the two tables, a JOIN would be exactly what you're looking for.
select t1.Name, t1.Age, t2.Sex, t1.Weight
from Table1 t1
join Table2 t2 on t1.Name = t2.Name and t1.Age = t2.Age
If there is any possibility that there is no match between the tables, start with the one with the larger number of records, then do a left outer join:
For example, assume Table1 has every person, but Table2 may be missing some:
select t1.Name, t1.Age, t2.Sex, t1.Weight
from Table1 t1
left join Table2 t2 on t1.Name = t2.Name and t1.Age = t2.Age
If you might have records in either table that aren't in the other, a full outer join would work:
select
coalesce(t1.Name, t2.Name) [Name]
,coalesce(t1.Age, t2.Age) [Age]
,t2.Sex
,t1.Weight
from Table1 t1
full join Table2 t2 on t1.Name = t2.Name and t1.Age = t2.Age
Since it doesn't look like you have a PRIMARY KEY
SELECT
t1.*,
t2.Sex
FROM
table1 t1
INNER JOIN
tabel2 t2 on t1.Name = t2.Name and t1.Age = t2.Age
This is most likely still going to cause some duplicates in larger datasets, but I'm assuming you are looking for logic and posted some dummy data.
JOIN is exactly what you need, but you need to join on a unique identifier. In this case, the Name column is unique for those two records, but usually JOINs are done on generated IDs such as CustomerID or ClientID. Like others have posted, you can use the other columns in conjunction with the Name column to ensure you don't get duplicates by adding those columns in the ON section of the JOIN clause.
SELECT t1.Name, t1.Age, t2.Sex, t1.Weight
FROM Table1 t1
INNER JOIN Table2 t2
ON (t1.Name = t2.Name)
I suggest adding a unique identifier as a primary key so JOINs are a lot easier to do in the future.
SELECT t1.*,t2.Sex
FROM table1 t1 LEFT JOIN table2 t2 ON t1.Name=t2.Name

MS Access 2007 Inner Join on Same Table

I have a table t1. It has columns [id] and [id2].
Select count(*) from t1 where id=1;
returns 31,189 records
Select count(*) from t1 where id=2;
returns 31,173 records
I want to know the records where id2 is in id=1 but not in id=2.
So, I use the following:
Select * from t1 a left join t1 b on a.id2=b.id2
Where a.id=2 And b.id=1
And b.id2 Is Null;
It returns zero records.
Using an inner join to see how many records have id2 in common, I do...
Select * from t1 a inner join t1 b on a.id2=b.id2
Where a.id=2 And b.id=1;
And that returns 31,060. So where are the extra records in my first query that don't match?
I am sure I must be missing something obvious.
Sample Data
id id2
1 101
1 102
1 103
2 101
2 102
My expected results is to find the record with '103' in it. 'id2' not shared.
Thanks for any help.
Jeff
You are attempting to do what is generally called an exclude join. This involves doing a LEFT JOIN between two tables, then using a WHERE clause to only select rows where the right table is null, i.e. there was no record to join. In this way, you select everything from the left table except what exists in the right table.
With this data, it would look something like this:
SELECT
t1.id,
t1.id2
FROM test_table t1
LEFT JOIN
(SELECT
id,
id2
FROM test_table
WHERE id = 2) t2
ON t2.id2 = t1.id2
WHERE t1.id = 1
AND t2.id IS NULL --This is what makes the exclude join happen
And here is a SQLFiddle demonstrating this in MySQL 5.7 with the sample data you provided.
I think maybe Access changes the left join to an inner join when you add a where clause to filter rows (I know SQL Server does this), but if you do the filtering in derived tables it should work:
select
a.*
from
(select * from t1 where id = 1) a
left join
(select * from t1 where id = 2) b
on a.id2 = b.id2
where b.id2 is null

Joining selected column to a table

I am try running this query and it takes long time because of the join i am using
SELECT T1.Id,T2.T2Id,T2.Col2
FROM Table1 T1
LEFT OUTER JOIN (SELECT TOP 1 Id, TT.T2Id,TT.Col2
FROM Table2 TT
WHERE TT.TypeId=3
ORDER BY TT.OrderId
)AS T2 ON T2 .Id=T1.Id
Thing is it doesn't let me do something like TT.Id=T1.Id with in the join query.
Is there any other way I can do this?
Try it with outer apply:
SELECT T1.Id, T2.T2Id, T2.Col2
FROM Table1 T1
OUTER APPLY (SELECT TOP 1 T2Id, T2.Col2
FROM Table2 TT
WHERE TT.TypeId = 3 AND TT.Id = T1.Id) T2
SELECT T1.Id, T2.T2Id, T2.Col2
FROM Table1 T1
OUTER APPLY (SELECT TOP 1 T2Id, T2.Col2
FROM Table2 TT
WHERE TT.TypeId = 3 AND T1.Id = TT.Id
Order by T2id desc) T2
I would use Outer Apply and T1.Id = TT.Id in the where condition since T1 is the parent table plus adding on order by - if needed for ordered result set
Well first of all your derived table will produce non deterministic results, as the top 1 row you return may differ each time you run it, even if the data in the table remains the same. You could put an order by clause in the the derived table to prevent that.
Is there an index on Table1.id? What exactly are you trying to achieve though, is it to return all rows from Table1, with just one row of many from Table2 that has the same ID?
If so I would look into using Cross Apply instead. Or maybe in this case Outer Apply. If I get a chance later I'll write up an example if needed, but in the mean time just Google Outer Apply for SQL Server.
Dan

SQL Joining three tables and using LEFT OUTER JOIN

I have three tables and two seperate SQL queries which are working correctly and I am having correct results.
If I try to join these three tables I am having null as result.
First query:
select T1.ID,T3.COMPANY
from T1,T3
where (T1.status!='CLOSED') and (T1.PRIORITY)>5 and T1.CLASSID=T3.CLASSID
Second query:
SELECT T1.ID, T2.DESCRIPTION
FROM T1
LEFT OUTER JOIN T2
ON T1.ID=T2.KEY
WHERE T1.status!='CLOSED'
AND (T2.CREATEDATE= (SELECT MAX(CREATEDATE)
FROM T2
WHERE T2.KEY=T1.ID))
I tried to join them but as result I am having null:
select T1.ID,T3.COMPANY,T2.DESCRIPTION
from T1
INNER JOIN T3 ON T1.CLASSID=T3.CLASSID
LEFT OUTER JOIN T2
ON T1.ID=T2.KEY
where (T1.status!='CLOSED') AND (T1.PRIORITY)>5
AND (T2.CREATEDATE= (SELECT MAX(CREATEDATE)
FROM T2
WHERE T2.KEY=T1.ID))
like it does not recognized last part for taking MAX value from T2 table.
What am I doing wrong? Thanks for help
Firstly, use an alias for the subquery on table T2.
T2.CREATEDATE =
(SELECT MAX(T2Alias.CREATEDATE)
FROM T2 AS T2Alias
WHERE T2Alias.KEY = T1.ID)
Secondly, consider moving this condition into the ON clause of the LEFT JOIN to table T2.
The first thing that jumps out at me is the new dependency on both T1.Priority > 5 and T2.CreateDate value being equal to the result of the inline query:
( AND (T1.PRIORITY) > 5
AND (T2.CREATEDATE =
(SELECT MAX(CREATEDATE) FROM T2 WHERE T2.KEY = T1.ID) )
Without the data it's difficult to check however this may be the issue

How can I do a FULL OUTER JOIN in MySQL?

I want to do a full outer join in MySQL. Is this possible? Is a full outer join supported by MySQL?
You don't have full joins in MySQL, but you can sure emulate them.
For a code sample transcribed from this Stack Overflow question you have:
With two tables t1, t2:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
The query above works for special cases where a full outer join operation would not produce any duplicate rows. The query above depends on the UNION set operator to remove duplicate rows introduced by the query pattern. We can avoid introducing duplicate rows by using an anti-join pattern for the second query, and then use a UNION ALL set operator to combine the two sets. In the more general case, where a full outer join would return duplicate rows, we can do this:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.id IS NULL
The answer that Pablo Santa Cruz gave is correct; however, in case anybody stumbled on this page and wants more clarification, here is a detailed breakdown.
Example Tables
Suppose we have the following tables:
-- t1
id name
1 Tim
2 Marta
-- t2
id name
1 Tim
3 Katarina
Inner Joins
An inner join, like this:
SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
Would get us only records that appear in both tables, like this:
1 Tim 1 Tim
Inner joins don't have a direction (like left or right) because they are explicitly bidirectional - we require a match on both sides.
Outer Joins
Outer joins, on the other hand, are for finding records that may not have a match in the other table. As such, you have to specify which side of the join is allowed to have a missing record.
LEFT JOIN and RIGHT JOIN are shorthand for LEFT OUTER JOIN and RIGHT OUTER JOIN; I will use their full names below to reinforce the concept of outer joins vs inner joins.
Left Outer Join
A left outer join, like this:
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
...would get us all the records from the left table regardless of whether or not they have a match in the right table, like this:
1 Tim 1 Tim
2 Marta NULL NULL
Right Outer Join
A right outer join, like this:
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
...would get us all the records from the right table regardless of whether or not they have a match in the left table, like this:
1 Tim 1 Tim
NULL NULL 3 Katarina
Full Outer Join
A full outer join would give us all records from both tables, whether or not they have a match in the other table, with NULLs on both sides where there is no match. The result would look like this:
1 Tim 1 Tim
2 Marta NULL NULL
NULL NULL 3 Katarina
However, as Pablo Santa Cruz pointed out, MySQL doesn't support this. We can emulate it by doing a UNION of a left join and a right join, like this:
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
UNION
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
You can think of a UNION as meaning "run both of these queries, then stack the results on top of each other"; some of the rows will come from the first query and some from the second.
It should be noted that a UNION in MySQL will eliminate exact duplicates: Tim would appear in both of the queries here, but the result of the UNION only lists him once. My database guru colleague feels that this behavior should not be relied upon. So to be more explicit about it, we could add a WHERE clause to the second query:
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
UNION
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;
On the other hand, if you wanted to see duplicates for some reason, you could use UNION ALL.
Using a union query will remove duplicates, and this is different than the behavior of full outer join that never removes any duplicates:
[Table: t1] [Table: t2]
value value
----------- -------
1 1
2 2
4 2
4 5
This is the expected result of a full outer join:
value | value
------+-------
1 | 1
2 | 2
2 | 2
Null | 5
4 | Null
4 | Null
This is the result of using left and right join with union:
value | value
------+-------
Null | 5
1 | 1
2 | 2
4 | Null
SQL Fiddle
My suggested query is:
select
t1.value, t2.value
from t1
left outer join t2
on t1.value = t2.value
union all -- Using `union all` instead of `union`
select
t1.value, t2.value
from t2
left outer join t1
on t1.value = t2.value
where
t1.value IS NULL
The result of the above query that is as the same as the expected result:
value | value
------+-------
1 | 1
2 | 2
2 | 2
4 | NULL
4 | NULL
NULL | 5
SQL Fiddle
#Steve Chambers: [From comments, with many thanks!]
Note: This may be the best solution, both for efficiency and for generating the same results as a FULL OUTER JOIN. This blog post also explains it well - to quote from Method 2: "This handles duplicate rows correctly and doesn’t include anything it shouldn’t. It’s necessary to use UNION ALL instead of plain UNION, which would eliminate the duplicates I want to keep. This may be significantly more efficient on large result sets, since there’s no need to sort and remove duplicates."
I decided to add another solution that comes from full outer join visualization and math. It is not better than the above, but it is more readable:
Full outer join means (t1 ∪ t2): all in t1 or in t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: all in both t1 and t2 plus all in t1 that aren't in t2 and plus all in t2 that aren't in t1:
-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value
union all -- And plus
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)
union all -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)
SQL Fiddle
None of the previous answers are actually correct, because they do not follow the semantics when there are duplicated values.
For a query such as (from this duplicate):
SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;
The correct equivalent is:
SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION -- This is intentionally UNION to remove duplicates
SELECT name FROM t2
) n LEFT JOIN
t1
ON t1.name = n.name LEFT JOIN
t2
ON t2.name = n.name;
If you need this to work with NULL values (which may also be necessary), then use the NULL-safe comparison operator, <=> rather than =.
MySQL does not have FULL-OUTER-JOIN syntax. You have to emulate it by doing both LEFT JOIN and RIGHT JOIN as follows:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
But MySQL also does not have a RIGHT JOIN syntax. According to MySQL's outer join simplification, the right join is converted to the equivalent left join by switching the t1 and t2 in the FROM and ON clause in the query. Thus, the MySQL query optimizer translates the original query into the following -
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
Now, there is no harm in writing the original query as is, but say if you have predicates like the WHERE clause, which is a before-join predicate or an AND predicate on the ON clause, which is a during-join predicate, then you might want to take a look at the devil; which is in details.
The MySQL query optimizer routinely checks the predicates if they are null-rejected.
Now, if you have done the RIGHT JOIN, but with WHERE predicate on the column from t1, then you might be at a risk of running into a null-rejected scenario.
For example, the query
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
gets translated to the following by the query optimizer:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'
So the order of tables has changed, but the predicate is still applied to t1, but t1 is now in the 'ON' clause. If t1.col1 is defined as NOT NULL
column, then this query will be null-rejected.
Any outer-join (left, right, full) that is null-rejected is converted to an inner-join by MySQL.
Thus the results you might be expecting might be completely different from what the MySQL is returning. You might think its a bug with MySQL's RIGHT JOIN, but that’s not right. Its just how the MySQL query optimizer works. So the developer in charge has to pay attention to these nuances when he/she is constructing the query.
I modified shA.t's query for more clarity:
-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value
UNION ALL -- include duplicates
-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t1.value IS NULL
In SQLite you should do this:
SELECT *
FROM leftTable lt
LEFT JOIN rightTable rt ON lt.id = rt.lrid
UNION
SELECT lt.*, rl.* -- To match column set
FROM rightTable rt
LEFT JOIN leftTable lt ON lt.id = rt.lrid
You can do the following:
(SELECT
*
FROM
table1 t1
LEFT JOIN
table2 t2 ON t1.id = t2.id
WHERE
t2.id IS NULL)
UNION ALL
(SELECT
*
FROM
table1 t1
RIGHT JOIN
table2 t2 ON t1.id = t2.id
WHERE
t1.id IS NULL);
You can just convert a full outer join, e.g.
SELECT fields
FROM firsttable
FULL OUTER JOIN secondtable ON joincondition
into:
SELECT fields
FROM firsttable
LEFT JOIN secondtable ON joincondition
UNION ALL
SELECT fields (replacing any fields from firsttable with NULL)
FROM secondtable
WHERE NOT EXISTS (SELECT 1 FROM firsttable WHERE joincondition)
Or if you have at least one column, say foo, in firsttable that is NOT NULL, you can do:
SELECT fields
FROM firsttable
LEFT JOIN secondtable ON joincondition
UNION ALL
SELECT fields
FROM firsttable
RIGHT JOIN secondtable ON joincondition
WHERE firsttable.foo IS NULL
SELECT
a.name,
b.title
FROM
author AS a
LEFT JOIN
book AS b
ON a.id = b.author_id
UNION
SELECT
a.name,
b.title
FROM
author AS a
RIGHT JOIN
book AS b
ON a.id = b.author_id
I fix the response, and works include all rows (based on the response of Pavle Lekic):
(
SELECT a.* FROM tablea a
LEFT JOIN tableb b ON a.`key` = b.key
WHERE b.`key` is null
)
UNION ALL
(
SELECT a.* FROM tablea a
LEFT JOIN tableb b ON a.`key` = b.key
where a.`key` = b.`key`
)
UNION ALL
(
SELECT b.* FROM tablea a
right JOIN tableb b ON b.`key` = a.key
WHERE a.`key` is null
);
Use:
SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;
It can be recreated as follows:
SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
LEFT JOIN t1 ON t1.id = tmp.id
LEFT JOIN t2 ON t2.id = tmp.id;
Using a UNION or UNION ALL answer does not cover the edge case where the base tables have duplicated entries.
Explanation:
There is an edge case that a UNION or UNION ALL cannot cover. We cannot test this on MySQL as it doesn't support full outer joins, but we can illustrate this on a database that does support it:
WITH cte_t1 AS
(
   SELECT 1 AS id1
   UNION ALL SELECT 2
   UNION ALL SELECT 5
   UNION ALL SELECT 6
   UNION ALL SELECT 6
),
cte_t2 AS
(
     SELECT 3 AS id2
   UNION ALL SELECT 4
   UNION ALL SELECT 5
   UNION ALL SELECT 6
   UNION ALL SELECT 6
)
SELECT  * FROM  cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;
This gives us this answer:
id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6
The UNION solution:
SELECT  * FROM  cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION    
SELECT  * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
Gives an incorrect answer:
id1  id2
NULL  3
NULL  4
1  NULL
2  NULL
5  5
6  6
The UNION ALL solution:
SELECT  * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT  * FROM  cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
Is also incorrect.
id1  id2
1  NULL
2  NULL
5  5
6  6
6  6
6  6
6  6
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6
Whereas this query:
SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
LEFT JOIN t1 ON t1.id = tmp.id
LEFT JOIN t2 ON t2.id = tmp.id;
Gives the following:
id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6
The order is different, but otherwise matches the correct answer.
Use a cross join solution:
SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2
ON 1=1;
It is also possible, but you have to mention the same field names in select.
SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id
The SQL standard says full join on is inner join on rows union all unmatched left table rows extended by nulls union all right table rows extended by nulls. Ie inner join on rows union all rows in left join on but not inner join on union all rows in right join on but not inner join on.
Ie left join on rows union all right join on rows not in inner join on. Or if you know your inner join on result can't have null in a particular right table column then "right join on rows not in inner join on" are rows in right join on with the on condition extended by and that column is null.
Ie similarly right join on union all appropriate left join on rows.
From What is the difference between “INNER JOIN” and “OUTER JOIN”?:
(SQL Standard 2006 SQL/Foundation 7.7 Syntax Rules 1, General Rules 1 b, 3 c & d, 5 b.)