Reputation: 300
I have two tables:
Table A:
id name
------------
1 Scott
2 Dan
3 Sam
Table B:
id name
------------
1 Dan
2 Andi
3 Jess
My result needs to be:
Id Name Found
1 Scott A
2 Dan C i.e. found in both
3 Sam A
2 Andi B
3 Jess B
I am able to do a UNION to fetch the result but how do I create the Found
column?
Upvotes: 2
Views: 387
Reputation: 775
Wrong answer You are looking for "union distinct" instead of just union. Corrected when I got the smack down and realized I mis read the question.
Generate a bitmask as below, using simple power notation to make it clearer that im just inserting ingrementing powers of 2 for the bitmask.
with data as (
SELECT Id,Name, 2^0 as bitmask FROM A
UNION ALL
SELECT Id,Name, 2^1 as bitmask FROM B
UNION ALL
SELECT Id,Name, 2^2 as bitmask FROM C)
SELECT Id,Name, SUM(bitmask)
FROM data
GROUP BY Id,Name
Upvotes: -1
Reputation: 27017
It looks to me like you effectively want to simultaneously do a left and right join. This technically isn't possible, since you always need to have one reference table. The only way I can think of doing this would be the following:
SELECT tableA.*
LEFT JOIN tableB.* USING name
UNION DISTINCT SELECT tableB.*
LEFT JOIN tableA USING name
After thinking some more, you may also be able to do:
SELECT tableA.*
LEFT JOIN tableB.* USING name
RIGHT JOIN tableB.* USING name
...although I'm not sure that's valid.
Upvotes: 0
Reputation: 4019
select tmp.name, case count(*) when 1 then tmp.tbl else 'C' end found
from (select id, name, 'A' tbl from TableA
union all
select id, name, 'B' tbl from TableB) as tmp
group by tmp.name;
+-------+-------+
| name | found |
+-------+-------+
| Andi | B |
| Dan | C |
| Jess | B |
| Sam | A |
| Scott | A |
+-------+-------+
Upvotes: 0
Reputation: 332571
Use:
SELECT CASE
WHEN y.name IS NULL THEN z.id
WHEN z.name IS NULL THEN y.id
ELSE y.id
END AS id,
x.name,
CASE
WHEN y.name IS NULL THEN 'B'
WHEN z.name IS NULL THEN 'A'
ELSE 'C'
END AS found
FROM (SELECT a.name
FROM TABLE_A a
UNION
SELECT b.name
FROM TABLE_B b) x
LEFT JOIN TABLE_A y ON y.name = x.name
LEFT JOIN TABLE_B z ON z.name = x.name
Alternative:
SELECT COALESCE(y.id, z.id) AS id,
x.name,
CASE
WHEN y.name IS NULL THEN 'B'
WHEN z.name IS NULL THEN 'A'
ELSE 'C'
END AS found
FROM (SELECT a.name
FROM TABLE_A a
UNION
SELECT b.name
FROM TABLE_B b) x
LEFT JOIN TABLE_A y ON y.name = x.name
LEFT JOIN TABLE_B z ON z.name = x.name
Upvotes: 4
Reputation: 838226
The way to do this is to use a FULL OUTER JOIN, but since this is not supported in MySQL you can instead use a combination of a LEFT JOIN and INNER JOIN and RIGHT JOIN.
(
SELECT A.Id, A.Name, 'A' AS Found
FROM A LEFT JOIN B ON A.Name = B.Name
WHERE B.Name IS NULL
)
UNION ALL
(
SELECT B.Id, B.Name, 'B' AS Found
FROM A RIGHT JOIN B ON A.Name = B.Name
WHERE A.Name IS NULL
)
UNION ALL
(
SELECT A.Id, A.Name, 'C' AS Found
FROM A JOIN B ON A.Name = B.Name
)
In fact, you only need a LEFT and RIGHT JOIN because you can handle the INNER JOIN at the same time as you do one of the other two joins. I think the above demonstrates the principle more clearly, but in practice the following will give better performance:
SELECT A.Id, A.Name, IF(B.Name IS NULL, 'A', 'C') AS Found
FROM A LEFT JOIN B ON A.Name = B.Name
UNION ALL
SELECT B.Id, B.Name, 'B' AS Found
FROM A RIGHT JOIN B ON A.Name = B.Name
WHERE A.Name IS NULL
Result:
Id Name Found 1 Scott A 2 Dan C 3 Sam A 2 Andi B 3 Jess B
Upvotes: 1