Multiple search between two tables - sql

I have two tables - the first (this is just an example but the original query is a pretty big)
item_id_t1
serial_num_t1
country_t1
customer
snapshot_date_t1
serial_num_trunc_t1
156648107
222-99950578
AAA
BBSS
12/1/2022
99950578
156648107
222-99950578
AAA
BBSS
11/1/2022
99950578
156648107
222-99950578
AAA
BBSS
1/1/2023
99950578
108279887
888-515179765
AAA
BBSS
12/1/2022
515179765
108279887
888-515179765
AAA
BBSS
11/1/2022
515179765
108279887
888-515179765
AAA
BBSS
11/1/2023
515179765
and the second one
serial_num_trunc_t2
serial_num_t2
up_ind_t2
99950578
333-99950578
1
515179765
888-515179765
1
Now, my first step would be to find a match based on serial_num_t1 = serial_num_t2 and the second part of the code should be to find all unmatched records but this time based on serial_num_trunc_t1 = serial_num_trunc_t2.
I started with CTE tables first
WITH t1 AS (SELECT * FROM t1),
t2 AS (SELECT * FROM t2)
SELECT a.*
(SELECT t1.*, t2.*
FROM t1
LEFT JOIN t2
ON serial_num_t1 = serial_num_t2) a
INNER JOIN
(SELECT t1.*, t2.*
FROM t1
LEFT JOIN t2
ON t1.serial_num_trunc_t1 = t2.serial_num_trunc_t1
WHERE q.up_ind_t2 <> 1) b
ON a.serial_num_trunc_t1 = b.serial_num_trunc_t2
and here I am stuck. How to compare unmatched values from table "a" again with table "b" based ON t1.serial_num_trunc_t1 = t2.serial_num_trunc_t2 WHERE t2.ip_ind_t2 <> 1
My final table should have six records (like t1) and "up_ind_t2" should be filled with 1 for all six records in the final table.
I would appreciate your help.

I am guessing, you want
WITH t1 AS (SELECT * FROM t1),
t2 AS (SELECT * FROM t2)
SELECT t1.*, t2.*
FROM t1
LEFT JOIN t2
ON serial_num_t1 = serial_num_t2
UNION ALL
SELECT t1.*, t2.*
FROM t1
INNER JOIN t2
ON t1.serial_num_trunc_t1 = t2.serial_num_trunc_t1
WHERE q.up_ind_t2 <> 1
as Query,the LEft JOIN doesn't make that much sense in the firstplace, so i removed ot from the second.
the second query implies that you have only 1 record for every serial_num_trunc_t2 and that is not equal to 1, if not you need to add limit

#nbk
It doesn't look like my solution. I added match_level in order to see from where a match comes: from LEFT JOIN or from INNER JOIN (UNION part of the code).
So, when I run your code I get the same results as before UNION ALL part
WITH t1 AS (SELECT * FROM ib),
t2 AS (SELECT * FROM qu)
SELECT t1.*, t2.*, 1 as match_level
FROM ib t1
LEFT JOIN qu t2
ON serial_num_t1 = serial_num_t2
UNION ALL
SELECT t1.*, t2.*, 2 as match_level
FROM ib t1
INNER JOIN qu t2
ON t1.serial_num_trunc_t1 = t2.serial_num_trunc_t2
WHERE t2.up_ind_t2 <> 1

Finally, this is what I needed.
with
ib as (
select *
from [dbo].[ib] i
left join [dbo].[qu] q
on i.serial_num_t1=q.serial_num_t2),
qu as (
select *
from [dbo].[ib] i
right join [dbo].[qu] q
on i.serial_num_trunc_t1=q.serial_num_trunc_t2)
select ff.*
from
(select *
from
(select ROW_NUMBER() OVER(PARTITION BY q.item_id_t1,
q.serial_num_t1,q.country_t1, q.customer, q.snapshot_date_t1,
q.up_ind_t2 ORDER BY q.snapshot_date_t1, q.up_ind_t2 DESC) AS it_row, q.*
from qu q
left join ib b
on q.serial_num_trunc_t2 = b.serial_num_trunc_t1) a
union
select 99 as it_row, zz.*
from qu as zz ) ff
where it_row = 1

Related

Select Multiple value from a table but group by one value

I am trying to select multiple values from two tables but i want to group by single value. I have tried using max(value) in select but max is returning the greatest one and not the exact one.
Here are my tables
The result i need is something like this
Result : HeadQuarterId - A, PropertyName - Name1, Amount - 102
HeadQuarterId - B, PropertyName - Name5, Amount - 30
Here is my query
SELECT Headquarterid,Max(PropertyName),sum(Amount)
FROM Table1 A LEFT OUTER JOIN Table2 B
ON A.Propetyid = B.PropertyId
GROUP BY Headquarterid
Here i have used Left Outer Join so that i will get all the data from left table even it is not available in right table.
Also i cannot use A.HeadquarterID = A.PropertyId in where condition since i have other dependency in that table. Please suggest someother way to achieve this result.
I think I understand. You want the headquarters with the maximum value, which happens to be A. If so:
select t1.*, sum(t2.amount) over () as total
from t1 left join
t2
on t2.PropertyId = t1.PropertyId
order by t2.amount desc
fetch first 1 row only;
Note: Not all databases support fetch first. It might be spelled limit or use select top (1) for instance.
I would recommend to get the headquartename per ID in a cte / subquery, then join it again to T1 and left join T1 to T2 in a second cte / subquery. This way you can calculate your sums basing on a single group:
WITH cte AS(
SELECT ROW_NUMBER() OVER (PARTITION BY t1.ID ORDER BY CASE WHEN t1.ID = t1.PROPERTYID THEN 0 ELSE 1 END) rn, t1.ID, t1.Name
FROM t1
),
cte2 AS(
SELECT c.name cName, t1.*, t2.Value
FROM t1
INNER JOIN cte c ON c.ID = t1.ID AND c.rn = 1
LEFT JOIN t2 ON t1.Propertyid = t2.propertyid
)
SELECT c2.id, c2.cname, sum(c2.value) value
FROM cte2 c2
GROUP BY c2.id, c2.cname
See SQLFiddle for details: http://sqlfiddle.com/#!18/8bf66/13/2
Of course you can build the first cte without the row_number only by using the WHERE ID = PROPERTYID - matter of taste I'd say...
As per your sample data you want window function :
select distinct t1.HeadQuarterId,
max(t1.PropertyName) over (partition by t1.HeadQuarterId) as PropertyName,
sum(t2.amount) over (partition by t1.HeadQuarterId) as amount
from t1 left join
t2
on t2.PropertyId = t1.PropertyId;
This provided the result i expected.
SELECT HQTRS1 AS headId,Max(LLORD1) AS headName, sum(Amount) AS amount
FROM
(SELECT DISTINCT HeadQuarterId AS HQTRS1, PropertyName AS LLORD1 FROM Table_1 WHERE HeadQuarterId = PropertyId) AS temp
INNER JOIN Table_1 AS A ON A.HeadQuarterId = temp.HQTRS1
LEFT OUTER JOIN Table_2 B
ON B.PropertyId = A.PropertyId
GROUP BY HQTRS1

Postgresql SELECT LEFT JOIN with columns on case

SELECT a1,a2,a3,a4,count(a5),b1,b2,b3
FROM table1
LEFT JOIN table2 ON a1=b1 AND a2=b2 (*here i need to join
next columns a3=b3 only if from table2 will be returned more than 1 records
other wise first 2 columns will be enough*)
group by a1,a2,a3,a4,a5,b1,b2,b3
Anybody knows how to perform this trick ?
Well, if I understand correctly:
FROM table1 t1 LEFT JOIN
(SELECT t2.*, COUNT(*) OVER (PARTITION BY b1, b2) as cnt
FROM table2 t2
)
ON t1.a1 = t2.b1 AND t1.a2 = t2.b2 AND
(cnt = 1 OR t1.a3 = t2.a3)

join 2 tables using oracle

There are 2 tables with data as below. The column 'ID' is the available in both tables. can someone please help me how do i get the desired output.
Table 1:
ID IND
101 Y
102 N
Table 2:
ID CD
101 A
101 B
101 C
101 D
102 A
Desired output:
ID CD IND
101 A Y
101 B
101 C
101 D
102 A N
What you have here is a join where you want to display the value of ind only on the first cd of each id. You can do this with the row_number() window function in a case expression:
SELECT t1.id, t2.cd, CASE rn WHEN 1 THEN t1.ind ELSE NULL END AS ind
FROM table1 t1
JOIN (SELECT id, cd, ROW_NUMBER() OVER (PARTITION BY ind ORDER BY cd ASC) AS rn
FROM table2) t2 ON t1.id = t2.id
This should do the trick.
SELECT table1.ID, table2.CD, table1.IND
FROM table1
INNER JOIN table2
ON table1.ID = table2.ID;
I would normally expect that if you had a table with a relationship in the ID column that you would want to do a simple inner join: http://sqlfiddle.com/#!4/e8e41/5
select t1.id, t2.cd, t1.ind
from t1
inner join t2
on t2.id = t1.id
However, that wouldn't give you the result you specified. Your IND field would be populated for each row.
Perhaps you're looking to join only where cd = 'A'. I don't know the point of that, but you could do something like this: http://sqlfiddle.com/#!4/e8e41/12
select t2.id, t2.cd, coalesce(t1.ind,' ') as ind
from t2
left join t1
on t2.id = t1.id
and t2.cd = 'A'
order by id, cd
Or perhaps you're looking to associate the ind with the first cd of each id. In that case, something like this (using a common table expression) might work for you: http://sqlfiddle.com/#!4/e8e41/20
with cte as (
select id, cd, row_number() over (partition by id order by cd) as rn
from t2
)
select t1.id, cte.cd, case when rn = 1 then t1.ind else ' ' end as ind
from t1
inner join cte
on t1.id = cte.id

SQL query - filter with cascading conditions

I've two tables T1 and T2 with the following columns -
T1
Project_ID
Category
Column_X
Column_Y
Column_Z
T2
Proj_ID
Category
Parent_Project_ID
I want to write a query to get records from T1 with the following condition -
Get Projects with Category = "A" from T1
Get child projects of the above filtered projects
I'm not sure how to check the second condition only with the results coming out of first condition.
What is needed?
Projects from T1 where Category is A
Child projects of projects obtained from condition 1
Adding sample data and desired results as requested -
To get all records from second table then you can use the following query.
SELECT
t2.*
FROM T1 t1
RIGHT OUTER JOIN T2 t2 ON t1.Project_ID = t2.Project_ID
WHERE t1.Category = "A"
SELECT * FROM T2 WHERE T2.Proj_ID IN ( SELECT Project_ID FROM T1 WHERE Category = 'A' )
This should do the job needed.
SELECT * from T2 as d
WHERE EXISTS ( SELECT * from T1 as d1 where d1.Category = 'A' and d1.Project_ID = d.Proj_ID )
SELECT * from T1 as d1 right join T2 as d2 on d1.Project_ID = d2.Proj_ID
WHERE d1.CodTert = 500
I've made an update, these query give the same result, one uses the JOIN one doesn't.
I'm assuming that T2.Parent_Project_ID and T1.Project_ID are related. If so, you can use this:
Select T3.*
From T1
Join T2 On T2.Parent_Project_ID = T1.Project_ID
Join T1 T3 On T3.Project_ID = T2.Proj_ID
Where T1.Category = 'A'
This would get only child projects of projects that have a category of 'A'.
EDIT:
Based on the output format that has been added to the question, the following query, which uses a LEFT OUTER JOIN would render the exact result required:
SELECT
T2.PROJ_ID Project_ID,
T2.Category,
T1.Column_X,
T1.Column_Y,
T1.Column_Z,
T2.Parent_Project_ID
FROM T1 T1_PARENTS
INNER JOIN T2
ON T2.Parent_Project_ID = T1.Project_ID and T1.Category = 'A'
INNER JOIN T2 T2_CHILDREN
ON T2_CHILDREN.PROJ_ID = T2.Parent_Project_ID OR T2_CHILDREN.Parent_Project_ID = T2.Parent_Project_ID
LEFT OUTER JOIN T1
ON T2_CHILDREN.PROJ_ID = T1.Project_ID;

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.)