Home > front end >  Left outer join involving three tables
Left outer join involving three tables

Time:12-29

From the 3 tables below I need to find 'John', who has a bike but not a car. I'm trying to use this syntax

Select <> from TableA A left join TableB B on A.Key = B.Key where B.Key IS null

so in practise I create a left join from the two tables but i'm bit confused how the where B.Key IS null fits in my query.

select t1.name from 
(table1 t1 join table3 on table3.table1id = t1.id join table2 t2 on table3.table2id = t2.id) 
left join 
(table1 t11 join table3 on table3.table1id = t11.id join table2 t22 on table3.table2id = t22.id) 
on t1.name = t11.name where t2.name = 'Bike' and t22.name = 'Car';

Table1

ID NAME
1 John
2 Nick

Table2

ID NAME
1 Bike
2 Car

Table3

table1ID table2ID
1 1
2 1
2 2

CodePudding user response:

If you want your query to run at all cost you can go for something monstrous like this:

select name from table1
left join (select table1Id, table2.id as CarId from table3 join table2 on table2.id = table3.table2Id where table2.name = 'Car') c on id=c.table1Id
left join (select table1Id, table2.id as BikeId from table3 join table2 on table2.id = table3.table2Id where table2.name = 'Bike') b on id=b.table1Id
where CarId is null and BikeId is not null

https://dbfiddle.uk/pbftUJQL

But at the end it is a rough equivalent of straightforward

select name from table1
where not exists (select * from table3 join table2 on table2.id = table3.table2Id where table1.id=table3.table1Id and table2.name = 'Car')
and exists (select * from table3 join table2 on table2.id = table3.table2Id where table1.id=table3.table1Id and table2.name = 'Bike')

You must analyze query plans to choose variant that offer better performance. It may be this one:

select table1.name from table1 join table3 on table1.id=table3.table1Id join table2 on table2.id = table3.table2Id
where table2.name = 'Bike'
and not exists (select * from table3 t3 join table2 t2 on t2.id = t3.table2Id where table1.id=t3.table1Id and t2.name = 'Car')

CodePudding user response:

From the 3 tables below I need to find John who has a bike but not a car.

I would rather use this approach, it allows you to include additional criteria (e.g. has a bike and a truck but not a car) by modifying the having clause instead of adding additional joins:

select table1.id, table1.name
from table3
join table1 on table3.table1id = table1.id
join table2 on table3.table2id = table2.id
group by table1.id, table1.name
having count(case when table2.name = 'bike' then 1 end) > 0
and    count(case when table2.name = 'car'  then 1 end) = 0

PS: your original query could be written like this (it was missing aliases and where clause):

select *
from table1
left join (
  table3 as table3_bike join
  table2 as table2_bike on table3_bike.table2id = table2_bike.id
) on table3_bike.table1id = table1.id and
     table2_bike.name = 'bike'
left join (
  table3 as table3_car join
  table2 as table2_car on table3_car.table2id = table2_car.id
) on table3_car.table1id = table1.id and
     table2_car.name = 'car'
where table2_bike.id is not null
and table2_car.id is null

This query has the potential to grow exponentially e.g. if John has two bikes and two cars it'll return 2 x 2 = 4 rows for John. Relational division using exists or having is recommended.

  • Related