I want to do a Full Outer Join in MySQL. Is this possible? Is a Full Outer Join supported by MySQL?
相关问题
- SQL join to get the cartesian product of 2 columns
- SQL join to get the cartesian product of 2 columns
- sql execution latency when assign to a variable
- Difference between Types.INTEGER and Types.NULL in
- php PDO::FETCH_ASSOC doesnt detect select after ba
MySql does not have FULL-OUTER-JOIN syntax. You have to emulate by doing both LEFT JOIN and RIGHT JOIN as follows-
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
andON
clause in the query. Thus, the MySql Query Optimizer translates the original query into the following -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.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 following query -
gets translated to the following by the Query Optimizer-
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 thats not right. Its just how the MySql query-optimizer works. So the developer-in-charge has to pay attention to these nuances when he is constructing the query.
The SQL standard says
full join on
isinner join on
rowsunion all
unmatched left table rows extended by nullsunion all
right table rows extended by nulls. Ieinner join on
rowsunion all
rows inleft join on
but notinner join on
union all
rows inright join on
but notinner join on
.Ie
left join on
rowsunion all
right join on
rows not ininner join on
. Or if you know yourinner join on
result can't have null in a particular right table column then "right join on
rows not ininner join on
" are rows inright join on
with theon
condition extended byand
that columnis null
.Ie similarly
right join on
union all
appropriateleft join on
rows.From What is the difference between “INNER JOIN” and “OUTER JOIN”?:
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:
Inner Joins
An inner join, like this:
Would get us only records that appear in both tables, like this:
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
andRIGHT JOIN
are shorthand forLEFT OUTER JOIN
andRIGHT 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:
...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:
Right Outer Join
A right outer join, like this:
...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:
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:
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:
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 theUNION
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 aWHERE
clause to the second query:On the other hand, if you wanted to see duplicates for some reason, you could use
UNION ALL
.Answer:
Can be recreated as follows:
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:
The UNION solution:
Gives an incorrect answer:
The UNION ALL solution:
Is also incorrect.
Whereas this query:
Gives the following:
The order is different, but otherwise matches the correct answer.
Using a
union
query will remove duplicates, and this is different than the behavior offull outer join
that never removes any duplicate:This is the expected result of
full outer join
:This is the result of using
left
andright Join
withunion
:[SQL Fiddle]
My suggested query is:
Result of above query that is as same as expected result:
[SQL Fiddle]
I decided to add another solution that comes from
full outer join
visualization and math, it is not better that above but more readable:[SQL Fiddle]
what'd you say about Cross join solution?