Full outer join like functionality but merging columns - sql

TableA
id | symbolA
1 m
2 n
4 o
TableB
id | symbolB
2 p
3 q
5 r
I'd like the following result:
id | symbolA | symbolB
2 n p
1 m NULL
4 o NULL
3 NULL q
5 NULL r
This is what I've already tried:
SELECT
TableA.id,
TableB.id,
TableA.symbolA,
TableB.symbolB
FROM
TableA
FULL OUTER JOIN
TableB
ON
TableA.id = TableB.id
NewTable
TableA.id | TableA.symbolA | TableB.id | TableA.symbolB
2 n 2 p
1 m NULL NULL
4 o NULL NULL
NULL NULL 3 q
NULL NULL 5 r
I've already tried a full outer join in combination with a coalesce but it doesn't exactly give me the the above desired output. The language is BigQuery, though I'm hoping there's nothing idiosyncratic about my request that wouldn't make it SQL language agnostic. Thanks.

You are almost there. You just need to merge the two id columns.
For this, you can use coalesce():
select
coalesce(a.id, b.id) id,
a.symbola,
b.symbolb
from tablea a
full outer join tableb b on a.id = b.id
The following syntax that joins with using should also work (most databases that support full join allow this):
select
id,
a.symbola,
b.symbolb
from tablea a
full outer join tableb b using(id)

Related

How to left join on two tables on just unique ids

I have two tables
Table 1:
color_id | label
---------|------
2 | 0
3 | 0
2 | 0
1 | 0
4 | 1
4 | 1
5 | 0
Table 2:
color_id
--------
2
1
4
I want a query that just gives me results for color_ids that are present in Table 2
So, I wrote:
SELECT *
FROM table1
LEFT JOIN table2
ON table1.color_id = table2.color_id
WHERE table2.color_id IS NOT NULL
however, the above gives duplicates as well. Meaning I get
2 | 0
2 | 0
1 | 0
4 | 1
4 | 1
I don't want the duplicates in the results. I just want unique items.
I want a query that just gives me results for color_ids that are present in Table 2
So, you shouldn't use LEFT JOIN in this case:
SELECT DISTINCT a.color_id, a.label
FROM table_1 a JOIN table_2 b
ON a.color_id = b.color_id
When you add the keyword Left (or Right or full) to a join specifier, you make the join an outer join. This means that you get all the rows from one side of the join, and only those rows from the other side that match. If you only want the rows from table_1 where the color_id is in table_2, then you want an inner join, specified by writing inner join or just writing join, without a left, right or full.
to eliminate duplicates, add the keyword distinct to the select clause...
Select distinct color_id, label
From table1 t1
join table2 t2
on t2.color_id = t1.color_id
Try the below query
SELECT DISTINCT color_id
FROM table_1 T1
WHERE EXISTS (SELECT 1 FROM table_2 T2 where T1.color_id = T2.color_id)
Use an inner join and a distinct clause:
SELECT DISTINCT table1.color_id, table1.label
FROM table1
INNER JOIN table2
ON table1.color_id = table2.color_id
What you are looking for is an INNER JOIN combined with a
SELECT distinct table1.color_id, tabl1.label
FROM table1
INNER JOIN table2 ON table1.color_id = table2.color_id
This eliminates any item in table1 not present in table 2 and duplicated rows.
the reason of that is you used Left Join, which will keep all obs in table1.
Try this:
SELECT table1.* FROM table1 Inner JOIN table2 ON table1.color_id = table2.color_id
this should works as actually all table2 obs are in table1. To be more serious, if table2 has obs that are not in table1 and you do want to keep them, replace inner join with right join.

Left join with additional join condition on Raima

I am struggeling with a left join on a Raima database. I'd like to add an additional join condition, but in this case the join behaves like an inner join, thus I am losing some of the expected results.
Example:
TABLE_A
ID
-------
1
2
3
4
.
TABLE_B
A_ID | B
--------
1 | 1
2 | 1
2 | 2
3 | 2
Query
select * from TABLE_A left join TABLE_B
on TABLE_A.ID = TABLE_B.A_ID
and TABLE_B.B = 1
I am expecting the following result:
1 1 1
2 2 1
3 null null
4 null null
E.g. on an Oracle 11g I get the expected result, but on the Raima it shows me only the first two results. What is the problem here and how to fix it?
You need this
select * from A left join
(select * from B where B=1) bd
on A.ID = bd.A_ID
The query you gave will not give you expected result in oracle also. This will.
PS: Please use different names for table and column

SQL Server: Subquery on a join

I have two tables with schema and data as below. Table A has an id and an associated name. Table B associates the id from Table A with a price and otherAttr. For each entry in Table A, there may be multiple entries with different prices in Table B, but otherAttr is the same for each entry.
Given an id for Table A, I would like to select the name, otherAttr, and the minimum price.
The below query returns multiple results, I need to write a query that will return a single result with the minimum price.
SELECT a.name, b.price, b.otherAttr
FROM A a
LEFT Join B b on b.idFromA = 1
WHERE a.id = 1
Table A Table B
id | name idFromA | price | otherAttr
-------- ---------------------------
1 | A 1 | 200 | abc
2 | B 1 | 300 | abc
1 | 400 | abc
2 | 20 | def
2 | 30 | def
2 | 40 | ef
I massively oversimplified my example. In addition to selecting the min price and otherAttr from Table B, I also have to select a bunch of other attributes from joins on other tables. Which is why I was thinking the Group By and Min should be a subquery of the join on Table B, as a way to avoid Grouping By all the attributes I am selecting (because the attributes being selected for vary programmatically).
The Actual query looks more like:
SELECT a.name, b.price, b.otherAttr, c.x, c.y, d.e, d.f, g.h....
FROM A a
LEFT Join B b on b.idFromA = 1
LEFT Join C c on something...
LEFT Join D d on something...
LEFT Join G g on something...
WHERE a.id = 1
To get this, you could use GROUP BY in an INNER query:
SELECT gd.name, gd.price,gd.otherAttr, c.x, c.y, d.e, d.f, g.h....
FROM
(SELECT a.id,a.name, MIN(b.price) as price, b.otherAttr
FROM A a
LEFT Join B b on b.idFromA = 1
WHERE a.id = 1
GROUP BY a.id,a.name,b.otherAttr) gd
LEFT Join B b on b.idFromA = 1
LEFT Join C c on something...
LEFT Join D d on something...
LEFT Join G g on something...
Try:-
SELECT a.name, MIN(b.price) minprice, b.otherAttr
FROM A a
LEFT Join B b ON a.Id = b.idFromA
GROUP BY a.name, b.otherAttr
HAVING a.id = 1
You could just do this instead:
SELECT a.name, MIN(b.price), MIN(b.otherAttr)
FROM TableA a
LEFT JOIN TableB b on b.idFromA = a.id
GROUP BY a.name
HAVING a.id = 1;
You need to inner join on price as well in addition to id on the subquery to intersect the right record(s) with the lowest price(s). Then TOP(1) will return only one of those records. You can avoid using TOP(1) if you can expand the conditions and group by fields in the subquery so you schema can assure only a single record is returned for that combination of attributes. Lastly, avoid left joins when intersecting sets.
SELECT TOP(1) p.id, p.price, b.OtherAttr
FROM B as b
INNER JOIN
(SELECT A.id, min(B.price) as price
FROM B
INNER JOIN A on A.id=B.idFromA and A.ID=1
GROUP BY A.id) as p on b.idFromA=p.id and b.price=p.price

Using Two Columns in SQL INNER JOIN

TableA
AID AName
1 Alpha
2 Bravo
3 Charlie
TableB
BID BName
1 Delta
2 Echo
3 Foxtrot
TableC
CID AID BID
1 1 null
2 null 2
3 3 null
I am using the following SQL statement:
SELECT C.CID, A.Name AS First, B.Name AS Second FROM TableC
INNER JOIN TableA ON TableC.AID = TableA.AID
INNER JOIN TableB ON TableC.BID = TableB.BID
but displays a blank record. The expected result should be:
CID First Second
1 Alpha
2 Echo
3 Charlie
Any suggestions?
Use LEFT JOIN instead of INNER JOIN.
SELECT C.CID, A.Name AS First, B.Name AS Second
FROM TableC
LEFT JOIN TableA ON TableC.AID = TableA.AID
LEFT JOIN TableB ON TableC.BID = TableB.BID
Use LEFT JOIN for each A, B table
SELECT C.CID, A.AName, B.BName
FROM C
LEFT JOIN A ON C.AID = A.AID
LEFT JOIN B ON C.BID = B.BID

Get records using left outer join

I have two tables as given below
Table A Table B Table C
============= ============== =========
Id Name Id AId CId Id Name
1 A 1 1 1 1 x
2 B 2 1 1 2 y
3 C 3 2 1 3 z
4 D 4 2 3 4 w
5 E 5 3 2 5 v
Now I want all the records of Table A with matching Id column CId from Table B where CId = 1.
So the output should be like below :
Id Name CId
1 A 1
2 B 1
3 C 1
4 D Null
5 E Null
Can anyone help me please?
This does what you want:
SELECT
A.Id,
A.Name,
CASE B.CId WHEN 1 THEN 1 ELSE NULL END AS CId
FROM
A LEFT JOIN B ON A.Id = B.Id
This is not about LEFT JOINing. You could as well do it with an INNER JOIN. When you don't want the 3 and 2 of column CId to appear you would still have to filter with WHERE and therefore the rows with Id 4 and 5 would not appear, which is not what you want.
EDIT:
Given this test data:
create table A (Id int, Name varchar(5));
insert into A values
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D'),
(5, 'E');
create table B (Id int, AId int, CId int);
insert into B values
(1,1,1),
(2,1,1),
(3,2,1),
(4,2,3),
(5,3,2);
my query does not give a cartesian product. Read and try before downvoting. Anyway, it was not clear to me what you want to achieve, now I've joined on AId column and with this query:
SELECT DISTINCT
A.Id,
A.Name
, CASE
WHEN B.CId > 1 THEN 1
WHEN B.CId = 1 THEN 1
ELSE NULL END AS CId
FROM
A LEFT JOIN B ON A.Id = B.AId
and it also gives the right output, like the first before. If this is still not what you want, your test data is wrong or I absolutely don't get it.
Try something like this:
SELECT TableA.Id, TableA.Name, TableB.CId
FROM TableA
LEFT OUTER JOIN TableB ON TableA.Id = TableB.CId
WHERE TableB.CId = 1
Hope this helps.
Edit:
The output you desired, can be achieved if you match TableA's ID column with TableB's ID column, NOT TableB's CId column. Try below which I tested in my pc and gives thee similar output you needed.
select TableA.Id, TableA.Name, TableB.CId
from TableA
left outer join TableB on TableA.Id = TableB.Id
and TableB.CId in
(
select TableB.CId
from TableB
left outer join TableC on TableB.CId = TableC.Id
WHERE TableB.CId = 1
)
group by TableA.Id, TableA.Name, TableB.CId
Please inform if I guess it right. Check the column names.