MySQL: Union of a Left Join with a Right Join - sql

Say we have the following tables t1 and t2:
t1:
id | column_1
-------------
1 | 1
2 | 2
t2:
id | column_2
-------------
2 | 2
3 | 3
and we want to find the following result:
id | column_1 | column_2
------------------------
1 | 1 |
2 | 2 | 2
3 | | 3
This basically is the union of a right join with a left join. The following code works but feels clumsy:
(
SELECT t1.id, t1.column_1, t2.column_2
FROM t1
LEFT JOIN t2 ON t1.id = t2.id
)
UNION
(
SELECT t2.id, t1.column_1, t2.column_2
FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
)
Is there a better way to achieve this?

select a.id, t1.column_1, t2.column_2
from (
select id from t1
union
select id from t2
) a
left outer join t1 on a.id = t1.id
left outer join t2 on a.id = t2.id

Try this one:
SELECT t1.id, t1.column_1, t2.column_2
FROM t1
FULL OUTER JOIN t2 ON (t1.id = t2.id)
Edit: Doesn't work, MySQL does not know FULL OUTER JOIN.
Have a look here:
http://www.xaprb.com/blog/2006/05/26/how-to-write-full-outer-join-in-mysql/

Haven't tried this myself, but this might work:
SELECT t1.id, t1.column_1, t2.column_2, t2a.column_2
FROM t1
LEFT JOIN t2 ON t1.id = t2.id
RIGHT JOIN t2 AS t2a ON t1.id = t2a.id

Related

How to find the same elements in tow arrays of two different tables in HIVE?

I have two tables like the follows:
table1:
id sid
1 | ['101', '102', '103']
2 | ['102', '101', '103']
3 | ['103', '101', '102']
table2:
id | sid
1 | ['101', '102', '103']
3 | ['102', '103']
and I wish to get the following table:
id sid
1 | ['101', '102', '103']
2 | ['102', '101', '103']
3 | ['103', '102']
Explanation: I wish to select the same elements in table1.sid and table2.sid with the same order in table1. Besides, if the id in table1 doesn't exist in table2, then keep the sid as it is in table1. What should I do?
You can use posexplode() to basically do what you want. Of course, all this array stuff is more complex in Hive than in other databases, particularly getting the results in the order you want:
select t1.id, collect_list(sid2)
from (select t1.id, t2.sid2, t1.pos1
from (table1 t1 lateral view
posexplode(t1.sid) as pos1, sid1
) left join
(table2 t2 lateral view
posexplode(t2.sid) as pos2, sid2
)
on t2.id = t1.id and t2.sid2 = t1.sid1
distribute by t1.id
order by t1.id, t1.pos1
) t
Something like this:
with t as (
select t1.id, collect_list(sid2) as sid
from (select t1.id, t2.sid2, t1.pos1
from (table1 t1 lateral view
posexplode(t1.sid) as pos1, sid1
) left join
(table2 t2 lateral view
posexplode(t2.sid) as pos2, sid2
)
on t2.id = t1.id and t2.sid2 = t1.sid1
distribute by t1.id
order by t1.id, t1.pos1
) t
select t1.id,
(case when size(t.sid) = 0 then t1.sid else t.sid end)
from t1 left join
t
on t1.id = t.id

SQL Join two table with key into different column

I have two table, in SQL; the first table(T1) is this:
ID
----
401
402
403
634
635
636
The second table(T2) is this:
ID1 | VALUE1 | ID2 | VALUE2
---- -------- ----- -------
401 | TEST | 634 | SAMPLE1
402 | MYVAL | 635 | TRUE
The result i need is this:
T1.ID | T2.ID1| T2.VALUE1 | T2.ID2 | T2.VALUE2
------ ------- ----------- -------- ----------
401 | 401 | TEST | 634 | SAMPLE1
402 | 402 | MYVAL | 635 | TRUE
634 | 401 | TEST | 634 | SAMPLE1
635 | 402 | MYVAL | 635 | TRUE
The value 403 and 636 of T1 must not be present in the result because don't have any reference in T2.
There is a way to accomplish this with some INNER JOIN? I'm using MS SQL Server 2017.
Wouldn't this just be in IN clause?
SELECT *
FROM dbo.Table1 T1
JOIN dbo.Table2 T2 ON T1.ID IN (T2.ID1,T2.ID2)
DB<>Fiddle
Suppose you can do simple join tables like this:
select t1.id, t2.id1, t2.value1, t2.id2, t2.value2
from t1
join t2 on (t1.id = t2.id1 or t1.id = t2.id2)
You need INNER JOIN AND UNION. Try like
(SELECT T1.ID , T2.ID1, T2.VALUE1 , T2.ID2 , T2.VALUE2 FROM
T1 INNER JOIN T2 ON t1.ID = T2.ID1)
UNION
(SELECT T1.ID , T2.ID1, T2.VALUE1 , T2.ID2 , T2.VALUE2 FROM
T1 INNER JOIN T2 ON t1.ID = T2.ID2)
Please, try with belwo query:
SELECT T1.ID , T2.ID1, T2.VALUE1 , T2.ID2 , T2.VALUE2
FROM dbo.Table1 T1
LEFT OUTER JOIN dbo.Table1 T2 ON T1.ID IN (T2.ID1,T2.ID2)
WHERE T2.ID1 IS NOT NULL
You could use OR in your JOIN condition:
SELECT T1.ID, T2.ID1, T2.VALUE1, T2.ID2, T2.VALUE2
FROM T1
INNER JOIN T2
ON T1.ID = T2.ID1 OR T1.ID = T2.ID2
Demo
Is this query output what you need?
SELECT t1.ID, t2.ID1, t2.VALUE1, t2.ID2, t2.VALUE2
FROM T1 t1
INNER JOIN T2 t2 ON t1.ID = t2.ID1
UNION
SELECT t1.ID, t2.ID1, t2.VALUE1, t2.ID2, t2.VALUE2
FROM T1 t1
INNER JOIN T2 t2 ON t1.ID = t2.ID2
You seem to want:
select v.id, t2.*
from table2 t2 cross apply
(values (t2.id1), (t2.id2)) as v(id);
I don't see what table1 has to do with the result set. Hence, join does not seem very useful.

how to union 3 table and group same id amount?

how to solve 3 table and group same id?
t1
----------
Id a
1 100
1 600
2 800
t2
----------
Id b
1 600
2 700
3 400
t3
----------
Id c
2 400
3 800
4 100
i want result like this:
Id a b c
------------------------------
1 700 600
2 800 700 400
3 400 800
4 100
Same id group by
do the fact you have id in several table youn should get, eg: using union ,all the id you need for join
select t.id, t1.a, t2.b, t3.c
from (
select id
from t1
union
select id
from t2
union
select id
from t3 ) AS t
left join t1 on t.id = t1.id
left join t2 on t.Id = t2.Id
left join t3 on t.Id = t3.Id
and if you need sum for a,b,c
select t.id, sum(t1.a), sum(t2.b), sum(t3.c)
from (
select id
from t1
union
select id
from t2
union
select id
from t3 ) AS t
left join t1 on t.id = t1.id
left join t2 on t.Id = t2.Id
left join t3 on t.Id = t3.Id
group by t.id
To ensure that you are taking all possible values use full outer join. Though this will not work in mySQL. If that is the case then look at this answer
select coalesce(t1.id,t2.id,t3.id) as id, sum(t1.a) as a, sum(t2.b) as b,sum(t3.c) as c
from t1
outer join t2
on t1.id = t2.id
outer join t3
on t1.id = t3.id
or t2.id = t3.id
group by id
Might be misunderstanding you, but looks like you just need to join the table more than doing a Union Operation on them. Below statement will only return records where all three tables have at least one record with the same id.
SQL would be:
SELECT TBL1.ID,
TBL1.A,
TBL2.B,
TBL3.C
FROM A TBL1 (NOLOCK)
INNER JOIN B TBL2 (NOLOCK) ON TBL1.ID = TBL2.ID
INNER JOIN C TBL3 (NOLOCK) ON TBL1.ID = TBL3.ID
Two questions:
1. Which SQL engine to you use?
2. and do you need to return values where one table does not have the id?

Distinct SQL Join two tables

I am trying to join two tables such that I am getting only a first match from the Right table instead of every match in Table2.
So if the query is:
SELECT T1.Name, T2.Dates
FROM Table1 T1
LEFT JOIN Table2 T2 ON T1.ID = T2 = ID
WHERE T1.Name = 'John'
I would like to see
John | 14/11/14
Joe | 10/10/2014
Jane | 25/10/2014
Instead of
John | 14/11/2014
John | 12/10/2014
Joe | 10/10/2014
Jane | 25/10/2014
Jane | 26/10/2014
Which join should I use?
You need to decide which row, you should select. Min or max as commented.
SELECT T1.Name,
( SELECT MIN( T2.Dates) FROM Table2 T2 WHERE T1.ID = T2 = ID) AS Dates
FROM Table1 T1
WHERE T1.Name = 'John'
The ANSI standard function row_number() can be a big help here. It is supported by most databases, so you can do:
SELECT T1.Name, T2.Dates
FROM Table1 T1 LEFT JOIN
(SELECT t2.*, ROW_NUMBER() OVER (PARTITION BY t2.ID ORDER BY t2.DATE DESC) as seqnum
FROM Table2 t2
) T2
ON T1.ID = T2.ID AND seqnum = 1
WHERE T1.Name = 'John';
In your question, you have only one column from the second table, so you can also do this with aggregation:
SELECT t1.ID, t1.Name, MAX(t2.Date)
FROM Table1 T1 LEFT JOIN
Table2 T2
ON t1.ID = t2.ID
WHERE T1.Name = 'John'
GROUP BY t1.ID, t1.Name;
Query
SELECT a.name,
MAX(b.Dates)
FROM tbl1 a
JOIN tbl2 b
ON a.id=b.id
WHERE a.name='John'
GROUP BY a.name;
Demo

MSSQL join with itself

I have two tables:
id
1
2
3
4
t1 AND t2
id | related_id
1 | 2
1 | 3
Where t2 is relationship table between t1 records. What is the best way to get desired output?
t1.id | t1_copy.id
1 | NULL -- want to get this NULL row
1 | 2
1 | 3
Simple JOIN would almost work, however it doesn't give me the first NULL row.
SELECT t1.id, t1_copy.id FROM t1
LEFT JOIN t2 ON t1.id = t2.id
LEFT JOIN t1 t1_copy ON t1_copy.id = t2.related_id
WHERE t1.id = 1
P.S: Yes, I do realize that desired output is wacky.
Seems like a simple UNION should do the trick
SELECT
id,
null as copy_id
FROM
t1
WHERE
exists (select * from t2 where t1.id = t2.id)
UNION ALL
SELECT
t1.id,
t2.related_id
FROM
t1
INNER JOIN t2
ON t1.id = t2.id
SQL Fiddle
SELECT DISTINCT t1.id, t1_copy.id FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.id
WHERE t1.id = 1