How can I join 4 tables - sql

Please help to modify the below code. I want to join these two select queries such that I can get a single output with records from two diff tables ? I have 4 tables,
table_a has the user id that I have to use to search
table_b1 has the foreign key for table_c which has the name that I want to get
table_b2 also has the foreign key for table_c which has the second name that I want to get too.
How can I combine below query in a single output?
my code
select c.name from table_a a
join table_b1 b1 on a.id=b1.id
join table_c c on b1.pri_id=c.id where a.user='abc'
select c.name from table_a a
join table_b2 b2 on a.id=b2.id
join table_c c on b2.pri_id=c.id where a.user='abc'

So you want to extract the names information in table_c for tables table_b1 and table_b2, which also join to table_a by the id column.
You'll need to add table_c twice to your query to retrieve name from table_b1 and name from table_b2, because the conditions to retrieve the name are different.
If you only want names when there is information in table_b1 AND table_b2 (and in table_c for each of the b tables), the query will be:
SELECT tc1.name name_b1, tc2.name name_b2
FROM table_a ta
JOIN table_b1 tb1 ON ta.id = tb1.id
JOIN table_b2 tb2 ON ta.id = tb2.id
JOIN table_c tc1 ON tb1.pri_id = tc1.id
JOIN table_c tc2 ON tb2.pri_id = tc2.id
WHERE ta.user = 'abc'
If there might not always be information for user in table_b1 or table_b2, but you want to retrieve information anyway, getting NULL when there isn't a name on one or both of the b tables, you'll need left joins:
SELECT tc1.name name_b1, tc2.name name_b2
FROM table_a ta
LEFT JOIN table_b1 tb1 ON ta.id = tb1.id
LEFT JOIN table_b2 tb2 ON ta.id = tb2.id
LEFT JOIN table_c tc1 ON tb1.pri_id = tc1.id
LEFT JOIN table_c tc2 ON tb2.pri_id = tc2.id
WHERE ta.user = 'abc'

May be you can use UnionAll here like this,
select c.name from table_a a
join table_b1 b1 on a.id=b1.id
join table_c c on b1.pri_id=c.id where a.user='abc'
union all
select c.name from table_a a
join table_b2 b2 on a.id=b2.id
join table_c c on b2.pri_id=c.id where a.user='abc'

Related

Table Self join

Table_a has columns : old_id and new_id . Following query gives planning region and organization code for old_id.
SELECT a.old_id,d.planning_region,b.organization_code
FROM table_a a
INNER JOIN table_b b ON a.old_id = b.organization_id
INNER JOIN table_c c ON c.organization_code = b.organization_code
INNER JOIN table_d d ON d.planning_location_id = b.organization_code
My requirement is get organization code for new_id too. So my output will be like this
old_id, planning_region ( of old_id ), organization_code (of old_id ) and organization_code (of new_id ).
Self Join should work but here in this case, Do I need to do self join of all 4 tables ?
Note: new_id also can be joined same as old_id with table_b.
If I am understanding correctly, you can add more joins.
If you just want the new organization_code:
SELECT
a.old_id,
d.planning_region,
b.organization_code,
b1.organization_code organization_code_new
FROM table_a a
INNER JOIN table_b b ON a.old_id = b.organization_id
INNER JOIN table_c c ON c.organization_code = b.organization_code
INNER JOIN table_d d ON d.planning_location_id = b.organization_code
INNER JOIN table_b b1 ON a.new_id = b1.organization_id
If you also want the planning_region, then we need to bring d as well:
SELECT
a.old_id,
d.planning_region,
b.organization_code,
d1.planning_region planning_region_new,
b1.organization_code organization_code_new
FROM table_a a
INNER JOIN table_b b ON a.old_id = b.organization_id
INNER JOIN table_c c ON c.organization_code = b.organization_code
INNER JOIN table_d d ON d.planning_location_id = b.organization_code
INNER JOIN table_b b1 ON a.new_id = b1.organization_id
INNER JOIN table_c c1 ON a.new_id = c1.organization_id
INNER JOIN table_d d1 ON d1.planning_location_id = b1.organization_code
Side note: it is not obvious what the purpose of table c is in the query (apart, maybe, filtering?).

If a row does not exist, check a second column on a join

I'm trying to join a table on a column
Select * From tableA a
LEFT JOIN tableB b
ON a.key = b.foreignkey
...
If that row cannot be found I want to join it to another column in table B. Is there an efficient way to do this.
Thanks
You can use COALESCE to join on the first non-NULL column.
Select * From tableA a
LEFT JOIN tableB b
ON a.key = COALESCE(b.foreignkey, b.another_column, b.another_column2)
It will try to join with b.foreignkey first. if that is NULL then b.foreignkey and so on.
Please find the example here.
Add another LEFT JOIN:
Select *
From tableA a left join
tableB b
on a.key = b.foreignkey left join
tableC c
on a.key = c.foreignkey and b.foreignkey is null;

How do I run the following query?

I have to table A and B.
The relationship is one to many.
In table B have foreign key from A.
TABLE A:
... fields
TABLE B:
f = foreignkey(A)
How to get all A without B ?
The query below is not working.
select TABLE_A.id, COUNT(TABLE_B.f)
from TABLE_A JOIN TABLE_B
ON (TABLE_A.id = TABLE_B.f)
GROUP BY TABLE_A.id HAVING COUNT(TABLE_B.f) = 0;
Use not exists?
select a.*
from table_a a
where not exists (select 1
from table_b b
where a.id = b.f
);
Or not in. Or left join with where.
Change JOIN to LEFT JOIN :
TABLE_A.id, COUNT(TABLE_B.f)
from TABLE_A
LEFT JOIN TABLE_B ON (TABLE_A.id = TABLE_B.f)
GROUP BY TABLE_A.id
HAVING COUNT(TABLE_B.f) = 0;
You can do a LEFT JOIN and take only the rows that have NULL in the column TABLE_B.f,
meaning that there is no TABLE_B.f to match TABLE_A.id:
SELECT TABLE_A.id
FROM TABLE_A LEFT JOIN TABLE_B
ON TABLE_A.id = TABLE_B.f
WHERE TABLE_B.f IS NULL;
assuming that TABLE_A.id is unique in TABLE_A,
otherwise use
SELECT DISTINCT TABLE_A.id
You can use the left join and check the nullity on right table.
SELECT TABLE_A.id,count(*)
FROM TABLE_A LEFT JOIN TABLE_B
ON TABLE_A.id = TABLE_B.f
WHERE TABLE_B.f IS NULL
group by TABLE_A.id;

Controlling join order in combining left join and inner join in Impala SQL

With this kind of data
create table table_a as select 1 as id1;
insert into table_a values (2),(3);
create table table_b as select 1 as id1, 'a' as id2;
insert into table_b values (1,'b');
create table table_c as select 'a' as id2;
I have the following kind of join in Impala sql:
select *
from table_a as a
left join table_b as b
on b.id1 = a.id1
left join table_c as c
on c.id2 = b.id2
yielding this result
"id1","id1","id2","id2"
1,1,b,
1,1,a,a
2,,,
3,,,
I would like the second join to be inner join instead of left join:
select *
from table_a as a
left join table_b as b
on b.id1 = a.id1
join table_c as c /* <- How to process this join first without using inner queries? */
on c.id2 = b.id2
and get this result:
"id1","id1","id2","id2"
1,1,a,a
2,,,
3,,,
Thus, I would like the inner join of table_b and table_c to take place first and only after to do the left join between table_a and (table_b inner joined to table_b).
Is possible to determine the join order in such manner without using inner queries?
With the help from #jarlh, I realized left-to-right processing of joins and then found that it is possible to use RIGHT joins:
select *
from table_c as c
join table_b as b
on b.id2 = c.id2
right join table_a as a
on a.id1 = b.id1;
in order to get the desired result:
"id2","id1","id2","id1"
a,1,a,1
,,,2
,,,3

How to write a transitive sql join in DB2?

I want something like the following.
SELECT fewCols, aColFromNewTbl FROM TABLE_A AS A
LEFT OUTER JOIN TABLE_B AS B ON A.ID = B.ID
LEFT OUTER JOIN TABLE_C AS C ON A.ID = C.ID
INNER JOIN A_NEW_TABLE AS NEWTBL ON NEWTBL.ID = B.ID;
Somehow I'm not able to achieve this functionality. Actually above query is suppose to join A with NEWTBL, but I'm joining it with B, which is already joined with A. For my results I want them to come exclusively from the join of NEWTBL and B. I don't know how I can get desired results?
Probably you need this:
SELECT fewCols, aColFromNewTbl
FROM TABLE_A AS A
LEFT OUTER JOIN TABLE_B AS B
INNER JOIN A_NEW_TABLE AS NEWTBL
ON NEWTBL.ID = B.ID
ON A.ID = B.ID
LEFT OUTER JOIN TABLE_C AS C
ON A.ID = C.ID;