I needed to run the following on MySQL, but it doesn’t allow FULL OUTER JOINs:
SELECT COALESCE(t0.date, t1.date, t2.date, t3.date) AS date,
COALESCE(t0.hits1, 0) AS hits0,
COALESCE(t1.hits2, 0) AS hits1,
COALESCE(t2.hits3, 0) AS hits2
COALESCE(t3.hits3, 0) AS hits3
FROM t0
FULL OUTER JOIN t1 ON t0.date = t1.date
FULL OUTER JOIN t2 ON COALESCE(t0.date, t1.date) = t2.date;
FULL OUTER JOIN t3 ON COALESCE(t0.date, t1.date, t2.date) = t3.date;
How can I do that in MySQL?
I understand how to do it for two tables, for example, as per this example, I could do:
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
Instead of:
SELECT * FROM t1 FULL OUTER JOIN t2
ON t1.id = t2.id
But how do I do my first example? The following I’ve come up with seems wrong:
SELECT COALESCE(t0.date, t1.date, t2.date, t3.date) AS date,
COALESCE(t0.hits1, 0) AS hits0,
COALESCE(t1.hits2, 0) AS hits1,
COALESCE(t2.hits3, 0) AS hits2,
COALESCE(t3.hits3, 0) AS hits3
FROM t0
LEFT JOIN t1 ON t0.date = t1.date
LEFT JOIN t2 ON COALESCE(t0.date, t1.date) = t2.date
LEFT JOIN t3 ON COALESCE(t0.date, t1.date, t2.date) = t3.date
UNION ALL
SELECT COALESCE(t0.date, t1.date, t2.date, t3.date) AS date,
COALESCE(t0.hits1, 0) AS hits0,
COALESCE(t1.hits2, 0) AS hits1,
COALESCE(t2.hits3, 0) AS hits2,
COALESCE(t3.hits3, 0) AS hits3
FROM t1
RIGHT JOIN t0 ON t0.date = t1.date
RIGHT JOIN t2 ON COALESCE(t0.date, t1.date) = t2.date
RIGHT JOIN t3 ON COALESCE(t0.date, t1.date, t2.date) = t3.date
WHERE t0.date IS NULL
AND t2.date IS NULL
AND t3.date IS NULL
Because the following bit seems too restrictive:
WHERE t0.date IS NULL
AND t2.date IS NULL
AND t3.date IS NULL
2
Answers
You can make this work by applying the union approach, but using separate CTEs for each sequential cross join:
This may, or may not, be a viable alternative approach for your situation. You could build a full union of all the dates first and then left join to each table:
or possibly replacing the union of all the dates with a recursive cte:
and you could add a having clause to remove dates with no hits: